Problem p01533 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <tuple>
#include <vector>
using namespace std;

enum { Y, X };
enum { COST, SCROLL, I, J };
typedef tuple<int, int> Point;
typedef tuple<int, int, int, int> T;

bool range(int x, int first, int last) { return first <= x && x <= last; }
int bitcount(int n) { return n ? (n & 1) + bitcount(n >> 1) : 0; }

int main() {
  int W, H;
  string line;
  Point start, goal;
  vector<Point> scroll, holl;

  cin >> W >> H;

  vector<vector<int>> field(H, vector<int>(W, 1));

  for (int i = 0; i < H; i++) {
    cin >> line;
    for (int j = 0; j < W; j++) {
      switch (line[j]) {
      case 'S':
        start = Point(i, j);
        break;
      case 'G':
        goal = Point(i, j);
        break;
      case 'M':
        scroll.push_back(Point(i, j));
        break;
      case '#':
        holl.push_back(Point(i, j));
        for (int dy = -2; dy <= 2; dy++) {
          for (int dx = -2; dx <= 2; dx++) {
            int y = i + dy, x = j + dx;
            if (!range(y, 0, H - 1))
              continue;
            if (!range(x, 0, W - 1))
              continue;
            if (dy == -2 || dy == 2 || dx == -2 || dx == 2)
              field[y][x] = max(2, field[y][x]);
            else
              field[y][x] = 3;
          }
        }
        break;
      case '.':
        break;
      default:
        break;
      }
    }
  }

  int ans;
  int dy[4] = {-1, 0, 1, 0};
  int dx[4] = {0, 1, 0, -1};

  set<T> visited;
  priority_queue<T> q;
  q.push(T(0, 0, get<Y>(start), get<X>(start)));
  while (!q.empty()) {
    T now = q.top();
    q.pop();

    if (visited.count(T(0, get<SCROLL>(now), get<I>(now), get<J>(now))))
      continue;
    visited.insert(T(0, get<SCROLL>(now), get<I>(now), get<J>(now)));

    //    printf("cost=%d; scroll=%d; point=(%d, %d);
    //    %d\\n",get<COST>(now),get<SCROLL>(now),get<I>(now),get<J>(now),q.size());

    if (get<I>(now) == get<Y>(goal) && get<J>(now) == get<X>(goal)) {
      if (bitcount(get<SCROLL>(now)) == scroll.size()) {
        ans = -get<COST>(now);
        break;
      }
    }
    for (int j = 0; j < scroll.size(); j++) {
      if (get<I>(now) == get<Y>(scroll[j]) &&
          get<J>(now) == get<X>(scroll[j])) {
        if ((get<SCROLL>(now) >> j) & 1) {
          break;
        } else {
          get<SCROLL>(now) ^= (1 << j);
        }
      }
    }

    bool ok = true;
    for (int j = 0; j < holl.size(); j++) {
      if (get<I>(now) == get<Y>(holl[j]) && get<J>(now) == get<X>(holl[j]))
        ok = false;
    }
    if (!ok)
      continue;

    for (int i = 0; i < 4; i++) {
      int y = get<I>(now) + dy[i], x = get<J>(now) + dx[i];
      if (!range(y, 0, H - 1))
        continue;
      if (!range(x, 0, W - 1))
        continue;
      q.push(T(get<COST>(now) - field[get<I>(now)][get<J>(now)],
               get<SCROLL>(now), y, x));
    }
  }

  //  for(int i=0;i<H;i++,cout<<endl)for(int j=0;j<W;j++)cout<<" "<<field[i][j];
  cout << ans << endl;
}

Error: TLE

Fixed submission:


#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <vector>
using namespace std;

#define Y first
#define X second
typedef pair<int, int> Point;

struct T {
  int cost, scroll, y, x;
  T() {}
  T(int a, int b, int c, int d) {
    cost = a;
    scroll = b;
    y = c;
    x = d;
  }
};
bool operator<(T a, T b) {
  if (a.cost != b.cost)
    return a.cost < b.cost;
  if (a.scroll != b.scroll)
    return a.scroll > b.scroll;
  if (a.y != b.y)
    return a.y > b.y;
  if (a.x != b.x)
    return a.x > b.x;
  return true;
}
bool operator==(T a, T b) {
  if (a.cost != b.cost)
    return false;
  if (a.scroll != b.scroll)
    return false;
  if (a.y != b.y)
    return false;
  if (a.x != b.x)
    return false;
  return true;
}

bool range(int x, int first, int last) { return first <= x && x <= last; }
int bitcount(int n) { return n ? (n & 1) + bitcount(n >> 1) : 0; }

int main() {
  int W, H;
  string line;
  Point start, goal;
  vector<Point> scroll, holl;

  cin >> W >> H;

  vector<vector<int>> field(H, vector<int>(W, 1));

  for (int i = 0; i < H; i++) {
    cin >> line;
    for (int j = 0; j < W; j++) {
      switch (line[j]) {
      case 'S':
        start = Point(i, j);
        break;
      case 'G':
        goal = Point(i, j);
        break;
      case 'M':
        scroll.push_back(Point(i, j));
        break;
      case '#':
        holl.push_back(Point(i, j));
        for (int dy = -2; dy <= 2; dy++) {
          for (int dx = -2; dx <= 2; dx++) {
            int y = i + dy, x = j + dx;
            if (!range(y, 0, H - 1))
              continue;
            if (!range(x, 0, W - 1))
              continue;
            if (dy == -2 || dy == 2 || dx == -2 || dx == 2)
              field[y][x] = max(2, field[y][x]);
            else
              field[y][x] = 3;
          }
        }
        break;
      case '.':
        break;
      default:
        break;
      }
    }
  }

  int ans;
  int dy[4] = {-1, 0, 1, 0};
  int dx[4] = {0, 1, 0, -1};
  vector<T> visited;
  priority_queue<T> q;
  q.push(T(0, 0, start.Y, start.X));
  while (!q.empty()) {
    T now = q.top();
    q.pop();

    T v = now;
    v.cost = 0;
    if (count(visited.begin(), visited.end(), v))
      continue;
    visited.push_back(v);

    if (now.y == goal.Y && now.x == goal.X) {
      if (bitcount(now.scroll) == scroll.size()) {
        ans = -now.cost;
        break;
      }
    }
    for (int j = 0; j < scroll.size(); j++) {
      if (now.y == scroll[j].Y && now.x == scroll[j].X) {
        if ((now.scroll >> j) & 1) {
          break;
        } else {
          now.scroll ^= (1 << j);
        }
      }
    }

    bool ok = true;
    for (int j = 0; j < holl.size(); j++) {
      if (now.y == holl[j].Y && now.x == holl[j].X)
        ok = false;
    }
    if (!ok)
      continue;

    for (int i = 0; i < 4; i++) {
      int y = now.y + dy[i], x = now.x + dx[i];
      if (!range(y, 0, H - 1))
        continue;
      if (!range(x, 0, W - 1))
        continue;
      q.push(T(now.cost - field[now.y][now.x], now.scroll, y, x));
    }
  }

  cout << ans << endl;
}