回溯加剪枝。只需DFS右、下两个方向即可,可以一行一行来。弄完一行之后看下该行所有数字是否都配对了,否则剪枝。还是得细心,两个 cnt 认错了找了大半天 bug 。。。
#includeusing namespace std;const int n = 7;int cnt;int dx[] = {1, 0}, dy[] = {0, 1};int dict[n][n], G[n][n+1], M[n][n+1], vis[n][n+1], use[30];bool judge(int x) { for (int j = 0; j <= n; j++) if (vis[x][j] == 0) return true; return false;}void DFS(int x, int y, int cnt2){ if(cnt2 == 28){ for(int i = 0; i < n; i++){ for(int j = 0; j <= n; j++){ printf("%4d", M[i][j]); } putchar('\n'); } putchar('\n'); cnt++; return; } if(x == n) return; if(y == n+1){ if (judge(x)) return; DFS(x + 1, 0, cnt2); return; } if(vis[x][y]){ DFS(x, y + 1, cnt2); return; } for(int i = 0; i < 2; i++){ int nx = x + dx[i], ny = y + dy[i]; int k = dict[G[x][y]][G[nx][ny]]; if(nx == n || ny == n+1 || vis[nx][ny] || use[k]) continue; M[x][y] = M[nx][ny] = k; vis[x][y] = vis[nx][ny] = use[k] = 1; DFS(x, y + 1, cnt2 + 1); vis[x][y] = vis[nx][ny] = use[k] = 0; }}int main(){ // freopen("data.in","r",stdin); // freopen("data.out","w",stdout); int c = 1; for(int i = 0; i < n; i++) for(int j = i; j < n; j++) dict[j][i] = dict[i][j] = c++; int T = 0; while(scanf("%d", &G[0][0]) != EOF){ for(int i = 0; i < n; i++){ for(int j = 0; j <= n; j++){ if(!i && !j) continue; scanf("%d", &G[i][j]); } } if(T++) printf("\n\n\n"); printf("Layout #%d:\n\n", T); for(int i = 0; i < n; i++){ for(int j = 0; j <= n; j++){ printf("%4d", G[i][j]); } putchar('\n'); } printf("\nMaps resulting from layout #%d are:\n\n", T); cnt = 0; DFS(0, 0, 0); printf("There are %d solution(s) for layout #%d.\n", cnt, T); } return 0;}