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

#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>

#define REP(i, s, n) for (int i = s; i < n; i++)
#define rep(i, n) REP(i, 0, n)
#define IINF (INT_MAX)
#define MAX_N 9

using namespace std;

struct Point {
  int x, y;

  Point(int x = IINF, int y = IINF) : x(x), y(y) {}

  bool operator<(const Point &a) const {
    if (x != a.x)
      return x < a.x;
    return y < a.y;
  }

  bool operator==(const Point &a) const { return (x == a.x && y == a.y); }
};

struct Data {
  vector<Point> snake;
  string next;
  int cost;

  Data(int cost = IINF) : cost(cost) {}

  bool operator<(const Data &a) const { return cost > a.cost; }
};

int dx[] = {+0, +1, +1, +0, -1, -1};
int dy[] = {-1, -1, +0, +1, +1, +0};
int n, k;
vector<Point> snake;
Point goal;
string next;
set<Point> stone;
set<vector<Point>> used;

int getDist(const Point &from, const Point &to) {
  Point np = Point(to.x - from.x, to.y - from.y);
  return max((int)abs(np.x + np.y), max((int)abs(np.x), (int)abs(np.y)));
}

bool check(vector<Point> &nsnake, int limit) {
  set<Point> body;
  rep(i, limit + 1) body.insert(nsnake[i]);
  if (body.size() != limit + 1)
    return false;
  rep(i, limit + 1) {
    int cnt = 0;
    rep(j, 6) {
      int nx = nsnake[i].x + dx[j];
      int ny = nsnake[i].y + dy[j];
      if (body.find(Point(nx, ny)) != body.end())
        cnt++;
    }
    if (i == 0 && cnt != 1)
      return false;
    if (i == n - 1 && cnt != 1)
      return false;
    if (i == 0 || i == n - 1)
      continue;
    if (cnt != 2)
      return false;
  }
  return true;
}

void makeNewSnake(vector<Data> &nsks, vector<Point> &nsnake, string &nnext,
                  const int &cost, int pos, bool sec) {

  if (pos >= n) {
    /*
    cout << "come here " << endl;
    rep(i,n)
      {
        cout << "(" << nsnake[i].x << ',' << nsnake[i].y << ") ";
      }
    cout << endl;
    */
    if (check(nsnake, n - 1)) {
      // cout << "check passed" << endl;
      Data d(cost);
      d.snake = nsnake;
      d.next = nnext;
      nsks.push_back(d);
    }
    // else cout << "check failed" << endl;
    return;
  }

  if (n == 1) {
    Point pre = nsnake[0];
    rep(i, 6) {
      int nx = pre.x + dx[i];
      int ny = pre.y + dy[i];
      nsnake[0] = Point(nx, ny);
      if (stone.find(nsnake[0]) != stone.end())
        continue;
      if (getDist(nsnake[0], goal) + cost > 20)
        continue;
      //
      makeNewSnake(nsks, nsnake, nnext, cost, pos + 1, sec);
    }
    return;
  }

  if (sec) {
    char prec;
    if (pos != 0) {
      prec = nnext[pos - 1];
      rep(j, 6) {
        int x = nsnake[pos - 1].x + dx[j];
        int y = nsnake[pos - 1].y + dy[j];
        if (Point(x, y) == nsnake[pos]) {
          nnext[pos - 1] = (char)('0' + j);
          break;
        }
      }
    }

    makeNewSnake(nsks, nsnake, nnext, cost, pos + 1, !sec);
    if (pos != 0)
      nnext[pos - 1] = prec;
    return;
  }

  makeNewSnake(nsks, nsnake, nnext, cost, pos + 1, !sec);

  Point pre = nsnake[pos];
  char prec = (pos - 1 >= 0 ? nnext[pos - 1] : 'X');

  if (pos == 0 || pos == n - 1) {
    int dir;
    if (pos == 0)
      dir = (nnext[pos] - '0') % 6;
    else
      dir = (nnext[pos - 1] - '0' + 3) % 6;

    int dd[2] = {+1, -1};

    rep(i, 2) {
      int ndir = (dir + dd[i] + 6) % 6;
      int nx = pre.x + dx[ndir];
      int ny = pre.y + dy[ndir];
      nsnake[pos] = Point(nx, ny);
      /*
      if(pos == 0)
        {
          nnext[pos] = (char)(((dir - dd[i] + 6) % 6 ) + '0');
        }
      else        nnext[pos-1] = (char)(((dir - dd[i] + 6 + 3) % 6 ) + '0');
      */
      // cout << "pos = " << pos << " (" << pre.x << "," << pre.y << ")"  <<
      // endl; cout << "(" << nsnake[pos].x << "," << nsnake[pos].y << ")" <<
      // endl;
      if (stone.find(nsnake[pos]) != stone.end())
        continue;
      if (pos == 0 && getDist(nsnake[pos], goal) + cost > 20)
        continue;
      // if(check(nsnake,pos))
      //{
      if (pos == n - 1) {
        rep(j, 6) {
          int x = nsnake[pos - 1].x + dx[j];
          int y = nsnake[pos - 1].y + dy[j];
          if (Point(x, y) == nsnake[pos]) {
            nnext[pos - 1] = (char)('0' + j);
            break;
          }
        }
      }
      makeNewSnake(nsks, nsnake, nnext, cost, pos + 1, !sec);
      //}
    }
    nsnake[pos] = pre;
    if (pos == n - 1)
      nnext[pos - 1] = prec;
  } else {
    if (nnext[pos] == nnext[pos - 1])
      return;
    int dir = (nnext[pos - 1] - '0' + 3) % 6;
    int fdir = IINF;
    if ((dir + 2) % 6 == nnext[pos] - '0') {
      fdir = (dir + 1) % 6;

    } else if ((nnext[pos] - '0' + 2) % 6 == dir) {
      fdir = (nnext[pos] - '0' + 1) % 6;
    }
    assert(fdir != IINF);

    Point pre = nsnake[pos];
    nsnake[pos] = Point(pre.x + dx[fdir], pre.y + dy[fdir]);
    /*
    rep(i,6)
      {
        int nx = nsnake[pos].x + dx[i];
        int ny = nsnake[pos].y + dy[i];
        if(Point(nx,ny) == nsnake[pos+1])
          {
            nnext[pos] = (char)('0'+i);
            break;
          }
      }
    */
    if (stone.find(nsnake[pos]) != stone.end()) {
      nsnake[pos] = pre;
      nnext[pos - 1] = prec;
      return;
    }
    // if(check(nsnake,pos))
    //{

    rep(j, 6) {
      int x = nsnake[pos - 1].x + dx[j];
      int y = nsnake[pos - 1].y + dy[j];
      if (Point(x, y) == nsnake[pos]) {
        nnext[pos - 1] = (char)('0' + j);
        break;
      }
    }

    makeNewSnake(nsks, nsnake, nnext, cost, pos + 1, !sec);
    //}
    nsnake[pos] = pre;
    nnext[pos - 1] = prec;
  }
}

void compute() {
  priority_queue<Data> Q;
  {
    Data d(0);
    d.next = next;
    d.snake.resize(n);
    rep(i, n) { d.snake[i] = snake[i]; }
    Q.push(d);
    used.insert(snake);
  }

  while (!Q.empty()) {
    Data data = Q.top();
    Q.pop();
    /*
    cout << "cur snake " << data.cost << endl;
    rep(i,n)
      {
        cout << "(" << data.snake[i].x+8000 << "," << data.snake[i].y-5000 << ")
    ";
      }
    cout << data.next.substr(0,n-1) << endl;
    */

    if (data.snake[0] == goal) {
      printf("%d\\n", data.cost);
      return;
    }

    int h = getDist(data.snake[0], goal);
    if (data.cost + h > 20)
      continue;

    vector<Data> nsks;

    vector<Point> nsnake(n);
    string nnext = data.next;
    nsnake = data.snake;

    makeNewSnake(nsks, nsnake, nnext, data.cost + 1, 0, false);
    nnext = data.next;
    nsnake = data.snake;

    makeNewSnake(nsks, nsnake, nnext, data.cost + 1, 0, true);

    // cout << "new snake : "  << nsks.size() << endl;
    rep(i, nsks.size()) {
      if (used.find(nsks[i].snake) == used.end()) {
        // cout << "insert" <<endl;
        used.insert(nsks[i].snake);
        Q.push(nsks[i]);
      }
    }
  }
}

int main() {
  while (scanf("%d", &n), n) {

    snake.resize(n);
    stone.clear();
    next.clear();
    used.clear();

    rep(i, n) {
      scanf("%d %d", &snake[i].x, &snake[i].y);
      if (i) {
        bool found = false;
        rep(j, 6) {
          int nx = snake[i - 1].x + dx[j];
          int ny = snake[i - 1].y + dy[j];
          if (nx == snake[i].x && ny == snake[i].y) {
            found = true;
            next += (char)('0' + j);
            break;
          }
        }
        assert(found);
      }
    }
    assert(next.size() == n - 1);

    scanf("%d", &k);

    rep(i, k) {
      int u, v;
      scanf("%d %d", &u, &v);
      stone.insert(Point(u, v));
    }

    scanf("%d %d", &goal.x, &goal.y);

    compute();
  }
  return 0;
}

Error: TLE

Fixed submission:

// もう無理,9時間以上やってたからもう無理無理本当きつい無理
/*
またやる気になったとき用メモ

タイムリミットがきつい、サンプルすら重くて全部できない
サンプルが間違っている
なぜかサンプルアウトプットよりも短いルートで到達している
メモリーもきつい
髪も薄くなってきたきつい

*/

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <unistd.h>
#include <vector>
#define F first
#define S second
#define pb push_back
#define all(n) n.begin(), n.end()
using namespace std;
typedef pair<int, int> P;
typedef vector<P> VP;
typedef vector<VP> VVP;
map<P, bool> TheRock; // if you smell what the roking is cookin'
map<P, int> G;
map<VP, int> used;
map<P, bool> Msnake;
int dx[] = {0, 1, 1, 0, -1, -1, 0};
int dy[] = {-1, -1, 0, 1, 1, 0, 0};
int n;
P GOAL;

bool CheckSnake(VP &snake, P p, int now) {
  for (int i = 0; i < snake.size(); i++) {
    if (i == now)
      continue;
    if (snake[i].F == p.F && snake[i].S == p.S)
      return true;
  }
  return false;
}

bool p_check(VP &snake, P p, int now) {
  if (TheRock[p])
    return false;

  if (CheckSnake(snake, p, now)) {
    // cerr << "OUT" << endl;
    return false;
  }

  int cnt = 0;
  for (int i = 0; i < 6; i++) {
    int nx, ny;
    nx = p.F + dx[i];
    ny = p.S + dy[i];
    if (CheckSnake(snake, P(nx, ny), now))
      cnt++;

    if (cnt == 0 || (cnt >= 2 && (i == 0 || i == snake.size() - 1)) ||
        cnt >= 3) {
      // cerr << "OUT2" << endl;
      return false;
    }
  }
  if (cnt == 0) {
    // cerr << "OUT3" << endl;
    return false;
  }
  return true;
}

bool Check(VP &snake, P p) {
  for (int i = 0; i < snake.size(); i++)
    if (snake[i] == p)
      return false;
  return true;
}

bool s_check(VP &snake) {

  map<P, bool> exist;
  map<P, int> fail_counter;
  for (int i = 0; i < snake.size(); i++) {
    exist[snake[i]] = true, exist[snake[i]]++;
    if (exist[snake[i]] >= 2)
      return false;
  }

  for (int i = 0; i < snake.size(); i++) {
    int cnt = 0;
    P p = snake[i];
    for (int j = 0; j < 6; j++) {
      int nx, ny;
      nx = p.F + dx[j], ny = p.S + dy[j];
      if (exist[P(nx, ny)])
        cnt++;
    }
    if (cnt == 0 || (cnt >= 2 && (i == 0 || i == snake.size() - 1)) ||
        cnt >= 3) {
      return false;
    }
  }
  return true;
}

void get_move(VP &snake, int now, bool flag, VVP &move) {

  if (now == snake.size()) { /*1*/

    bool ok = true;
    map<P, bool> exist;
    map<P, int> NARIYOSHI_X;
    for (int i = 0; i < snake.size(); i++)
      if (TheRock[snake[i]]) {
        ok = false;
        break;
      }

    for (int i = 0; i < snake.size(); i++) {
      exist[snake[i]] = true, NARIYOSHI_X[snake[i]]++;
      if (NARIYOSHI_X[snake[i]] >= 2) {
        ok = false;
        break;
      }
    }

    for (int i = 0; i < snake.size(); i++) {
      int cnt = 0;
      P p = snake[i];
      for (int j = 0; j < 6; j++) {
        int nx, ny;
        nx = p.F + dx[j], ny = p.S + dy[j];
        if (exist[P(nx, ny)])
          cnt++;
      }
      if (cnt == 0 || (cnt >= 2 && (i == 0 || i == snake.size() - 1)) ||
          cnt >= 3) {
        // cout << i << "'cnt = " << cnt << endl;
        ok = false;
        break;
      }
    }

    if (ok)
      move.push_back(snake);
    return;
  } /*1*/

  if (flag && now % 2 != 0) {
    get_move(snake, now + 1, flag, move);
    return;
  } else if (!flag && now % 2 == 0) {
    get_move(snake, now + 1, flag, move);
    return;
  }

  P p = snake[now];
  for (int i = 0; i < 7; i++) {
    p.F += dx[i], p.S += dy[i];
    P pre = snake[now];
    snake[now] = p;
    // if(s_check(snake))
    //{
    get_move(snake, now + 1, flag, move);
    //}
    p.F -= dx[i], p.S -= dy[i];
    snake[now] = pre;
    snake[now] = p;
  }
}

void rec(VP &snake, int cnt) {
  if (G[GOAL] != 0 && cnt >= G[GOAL])
    return;
  for (int i = 0; i < snake.size(); i++)
    if (TheRock[snake[i]])
      return;

  /*
  cout << "cnt = " << cnt << endl;
  for(int i=0;i<snake.size();i++)
    {
      cout << snake[i].F << " " << snake[i].S << endl;
    }
  cout << endl;
  */

  if (snake[0] == GOAL) {

    // cout << "eojfjpaweojfawepfojawepf == " << cnt-1 << endl;
    if (G[snake[0]] == 0)
      G[snake[0]] = cnt;
    else
      G[snake[0]] = min(G[snake[0]], cnt);
    return;
  }

  if (abs(GOAL.F - snake[0].F) + abs(GOAL.S - snake[0].S) + cnt >= 10)
    return;

  if (cnt >= 20)
    return;

  VVP move;
  get_move(snake, 0, true, move);  // even
  get_move(snake, 0, false, move); // odd

  /*
  cout << "cnt = " << cnt << endl;
  for(int i=0;i<move.size();i++)
    {
      cout << i << " - th" << endl;
      for(int j=0;j<move[i].size();j++)
        {
          cout << move[i][j].F << " " << move[i][j].S << endl;
        }
      cout << endl;
    }
  */
  if (move.size() == 0)
    return;

  VP pre_snake = snake;
  for (int i = 0; i < move.size(); i++) {
    if (used[move[i]] != 0 && used[move[i]] <= cnt)
      continue;
    used[move[i]] = cnt;
    snake = move[i];

    if (!(abs(GOAL.F - snake[0].F) + abs(GOAL.S - snake[0].S) + cnt >= 10))
      rec(snake, cnt + 1);
    snake = pre_snake;
  }
}

void Do(VP &snake) {
  rec(snake, 0);
  cout << G[GOAL] << endl;
}

int main() {

  /*
  vector<P> test_snake;
  VVP test_vvp;
  test_snake.push_back(P(2,-2));
  test_snake.push_back(P(2,-1));
  test_snake.push_back(P(1,0));

  get_move(test_snake,0,true,test_vvp);
  cout << "even" << endl;
  for(int i=0;i<test_vvp.size();i++)
    {
      cout << i << " - th" << endl;
      for(int j=0;j<test_vvp[i].size();j++)
        {
          cout << test_vvp[i][j].F << " " << test_vvp[i][j].S << endl;
        }
    }
  test_vvp.clear();
  get_move(test_snake,0,false,test_vvp);
  cout << "odd" << endl;
 for(int i=0;i<test_vvp.size();i++)
    {
      cout << i << " - th" << endl;
      for(int j=0;j<test_vvp[i].size();j++)
        {
          cout << test_vvp[i][j].F << " " << test_vvp[i][j].S << endl;
        }
    }

  return 0;
  */
  clock_t st, ed;

  while (scanf("%d", &n), n) {
    TheRock.clear(), G.clear(), used.clear();
    VP snake;
    for (int i = 0; i < n; i++) {
      int x, y;
      scanf("%d %d", &x, &y);
      snake.pb(P(x, y));
      Msnake[P(x, y)] = true;
    }
    G[snake[0]] = 20;
    used[snake] = 0;

    int k;
    cin >> k;

    for (int i = 0; i < k; i++) {
      int u, v;
      cin >> u >> v;
      TheRock[P(u, v)] = true;
    }
    cin >> GOAL.F >> GOAL.S;
    st = clock();
    Do(snake);
    ed = clock();
    // cout << setiosflags(ios::fixed) << setprecision(10) <<
    // (double)(ed-st)/CLOCKS_PER_SEC << endl;
  }
  return 0;
}

/*
void get_move(VP snake,int now,VVP& vvp)
{
  if(now == snake.size())
    {
      vvp.push_back(snake);
      return;
    }

  P p = P(snake[now].F,snake[now].S);
  for(int i=0;i<7;i++)
    {
      p.F += dx[i], p.S += dy[i];
      if(p_check(snake,p,now))
        {
          P pre = snake[now];
          snake[now] = p;
         get_move(snake,now+1,vvp);
          snake[now] = pre;
        }
      p.F -= dx[i], p.S -= dy[i];
    }

}
*/