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

#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;

int nx[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}}; // 上 左 右 下  置换顺序

// 各个数字应在位置对照表
int goal[16][2] = {{3, 3}, {0, 0}, {0, 1}, {0, 2},  // 0 1 2 3
                   {0, 3}, {1, 0}, {1, 1}, {1, 2},  // 4 5 6 7
                   {1, 3}, {2, 0}, {2, 1}, {2, 2},  // 8 9 10 11
                   {2, 3}, {3, 0}, {3, 1}, {3, 2}}; // 12 13 14 15

int map[4][4], map2[16], limit;
// mit全部的曼哈顿距离之和
int flag, length;

int hv(int a[][4]) // 估价函数,曼哈顿距离,小于等于实际总步数
{
  int cost = 0;
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++) {
      int w = map[i][j];
      if (w != 0)
        cost += abs(i - goal[w][0]) + abs(j - goal[w][1]);
    }
  }
  return cost;
}

void dfs(int x, int y, int len, int pre_move) // sx,sy是空格的位置
{
  if (flag)
    return;
  int dv = hv(map);
  if (len == limit) {
    if (dv == 0) // 成功 退出
    {
      flag = 1;
      length = len;
      return;
    } else
      return; // 超过预设长度 回退
  } else if (len < limit) {
    if (dv == 0) // 短于预设长度 成功 退出
    {
      flag = 1;
      length = len;
      return;
    }
  }
  for (int i = 0; i < 4; i++) {
    if (i + pre_move == 3 && len > 0)
      continue; // 不和上一次移动方向相反,对第二步以后而言
    int tx = x + nx[i][0];
    int ty = y + nx[i][1];
    if (tx >= 0 && tx < 4 && ty >= 0 && ty < 4) {
      swap(map[x][y], map[tx][ty]);
      int p = hv(map);
      if (p + len <= limit && flag == 0) {
        dfs(tx, ty, len + 1, i);
        if (flag)
          return;
      }
      swap(map[x][y], map[tx][ty]);
    }
  }
}

int main() {
  int t = 1;
  while (t--) {
    int x1, y1;
    for (int i = 0; i < 16; i++) // map一维map2二维
    {
      scanf("%d", &map2[i]);
      if (map2[i] == 0) {
        x1 = i / 4;
        y1 = i % 4;
        map[x1][y1] = 0;
      } else {
        map[i / 4][i % 4] = map2[i];
      }
    }

    limit = hv(map);
    //        printf("limit===%d\\n",limit);
    flag = 0;
    length = 0;
    while (flag == 0 && length <= 45) // 要求45步之内到达
    {
      dfs(x1, y1, 0, 0);
      if (flag == 0)
        limit++; // 得到的是最小步数
    }
    if (flag)
      printf("%d\\n", length);
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <ctype.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
#define LL long long
map<LL, int> mm;
LL fac[20];
const LL inf = (LL)1 << 62;
int n;
int G[20];
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};

int getG(int st[]) {
  int dis = 0;
  for (int i = 0; i < n * n; i++) {
    int d = st[i] - 1;
    if (st[i] != 16)
      dis += abs(d / n - i / n) + abs(d % n - i % n);
  }
  return dis;
}
LL getH(int st[]) {
  LL sum = 0;
  for (int i = 1; i < n * n; i++) {
    int k = 0;
    for (int j = 0; j < i; j++)
      if (G[j] > G[i])
        k++;
    sum += k * fac[i];
  }
  return sum;
}
void dfs(int pos, int step, int g) {
  if (step == g && getG(G) == 0) {
    printf("%d\\n", step);
    exit(0);
  }
  if (step > g)
    return;
  //    printf("----------%d\\n",step);
  //    for(int i=0;i<n;i++)
  //    {
  //        for(int j=0;j<n;j++)
  //            printf("%d ",G[i*4+j]);
  //        printf("\\n");
  //    }
  LL h;
  // mm[h]=1;
  for (int i = 0; i < 4; i++) {
    int ty = pos / 4 + dir[i][0];
    int tx = pos % 4 + dir[i][1];
    if (ty < 0 || ty >= n || tx < 0 || tx >= n)
      continue;
    swap(G[pos], G[ty * 4 + tx]);
    h = getH(G);
    if (step + getG(G) <= g && !mm[h]) {
      mm[h] = 1;
      dfs(ty * 4 + tx, step + 1, g);
      mm[h] = 0;
    }
    swap(G[pos], G[ty * 4 + tx]);
  }
}
int main() {
  n = 4;
  fac[1] = 1;
  for (int i = 2; i <= 16; i++)
    fac[i] = fac[i - 1] * i;
  int pos;
  for (int i = 0; i < 16; i++) {
    scanf("%d", &G[i]);
    if (G[i] == 0)
      G[pos = i] = 16;
  }
  int g = getG(G);
  mm.clear();
  while (g <= 45) {
    dfs(pos, 0, g);
    g++;
  }
  return 0;
}
/*
1 2 3 4
5 6 7 8
9 10 0 12
13 14 11 15
*/