先给一个我最先写的一个代码吧。总体思路是这样的,对于每个输入的点,都进行一次广搜,打出到达其他点的最短路径(这个效率相比于floyd太低了)再加在ans数组当中,最后搜索出最小值,并输出。虽然这个代码能过很多数据,但是 Discuss 里A1A2A3H2H5H6H7H8C1C2C5C6C7E2E3E4E5E6E7E8 就过不了。
至于原因还望大牛们给予指点。我预测可能是广搜有问题,我原以为,用广搜打出的路径表一定就严格递增的,所以我就这么写了,不过后来还是有问题,望各位指点啊。
我的错误代码如下:
#include <stdio.h> #include <iostream> #include <string.h> #include <queue> using namespace std; #define LEN 8 #define MIN(a,b) (a<b?a:b) int ans[LEN][LEN]; int king[LEN][LEN]; int knight[LEN][LEN]; int flag[LEN][LEN]; int count = 0; int point[8][2] = { {-1, -2},{-1, 2},{1, -2},{1, 2}, {-2, -1},{-2, 1},{2, -1},{2, 1} }; /* void find(int x, int y, int n) { if(x < 0 || x >= LEN || y < 0 || y >= LEN) { return; } if(count > 128) return; count++; knight[x][y] = MIN(knight[x][y], n+1); find(x-1, y-2, knight[x][y]); find(x-1, y+2, knight[x][y]); find(x+1, y-2, knight[x][y]); find(x+1, y+2, knight[x][y]); find(x-2, y-1, knight[x][y]); find(x-2, y+1, knight[x][y]); find(x+2, y-1, knight[x][y]); find(x+2, y+1, knight[x][y]); } */ int _abs(int a) { return a < 0 ? (-a) : (a); } void find(int sx, int sy) { queue<int> queue; while(!queue.empty()) { queue.pop(); } queue.push(sx); queue.push(sy); queue.push(0); flag[sx][sy] = 1; while(!queue.empty()) { int x = queue.front(); queue.pop(); int y = queue.front(); queue.pop(); int n = queue.front(); queue.pop(); for(int i = 0; i < 8; i++) { int xx = x+point[i][0]; int yy = y+point[i][1]; if(xx < 0 || xx >= LEN || yy < 0 || yy >= LEN) { continue; } if(flag[xx][yy]) { continue; } flag[xx][yy] = 1; knight[xx][yy] = n+1; queue.push(xx); queue.push(yy); queue.push(n+1); } } } void init() { for(int i = 0; i < LEN; i++) { for(int j = 0; j < LEN; j++) { knight[i][j] = 99999; } } knight[0][0] = 0; } void pr() { for(int i = 0; i < LEN; i++) { for(int j = 0; j < LEN; j++) { cout<< ans[i][j]<< " "; } cout<< endl; } cout<< endl; } void pri() { for(int i = 0; i < LEN; i++) { for(int j = 0; j < LEN; j++) { cout<< knight[i][j]<< " "; } cout<< endl; } cout<< endl; } int main() { char str[10000]; int index, i, j, k; memset(king, 0, sizeof(king)); memset(flag, 0, sizeof(flag)); init(); king[0][0] = 0; for(i = 1; i < LEN; i++) { king[0][i] = king[0][i-1] + 1; king[i][0] = king[i-1][0] + 1; } for(i = 1; i < LEN; i++) { for(j = 1; j < LEN; j++) { king[i][j] = MIN(king[i][j-1], MIN(king[i-1][j], king[i-1][j-1])) + 1; } } while(gets(str)) { memset(ans, 0, sizeof(ans)); int k1 = str[0]-'A'; int k2 = str[1]-'0'-1; for(i = 0; i < LEN; i++) { for(j = 0; j < LEN; j++) { ans[i][j] += _abs(king[i][j]-king[k1][k2]); } } // pr(); for(index = 2; str[index] != '\0'; index += 2) { int t1 = str[index]-'A'; int t2 = str[index+1] - '0' - 1; memset(knight, 0, sizeof(knight)); memset(flag, 0, sizeof(flag)); find(t1, t2); // pri(); for(i = 0; i < LEN; i++) { for(j = 0; j < LEN; j++) { ans[i][j] += _abs(knight[i][j]-knight[t1][t2]); } } // pr(); } int min = 99999; for(i = 0; i < LEN; i++) { for(j = 0; j < LEN; j++) { min = MIN(min, ans[i][j]); } } printf("%d\n", min); memset(str, 0, sizeof(str)); } return 0; }
正确的 DP + floyd 解法, 其实最主要的就是把原来的那个 map 转换成为一个新的二维数组。
A1A2A3H2H5H6H7H8C1C2C5C6C7E2E3E4E5E6E7E8 #include <cstdio> #include <iostream> #include <cstring> #include <string> using namespace std; #define MAX 8 const int INF = (1<<20); int dirKing[8][2] = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}}; int dirKnight[8][2] = {{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{1,-2},{-1,2},{1,2}}; char str[MAX*MAX*2+5]; int king[MAX*MAX][MAX*MAX], knight[MAX*MAX][MAX*MAX]; int step[MAX*MAX], num; inline int min(int a,int b) { return a < b ? a : b; } void init() { for(int i = 0; i < MAX*MAX; ++i) for(int j = 0; j < MAX*MAX; ++j) king[i][j] = knight[i][j] = (i == j ? 0 : INF); for(int i = 0; i < MAX*MAX; ++i) { int x = i/8; int y = i%8; for(int j = 0; j < 8; ++j) { int xx = x+dirKing[j][0]; int yy = y+dirKing[j][1]; if(xx >= 0 && xx < MAX && yy >= 0 && yy < MAX) king[i][8*xx+yy] = 1; } for(int j = 0; j < 8; ++j) { int xx = x+dirKnight[j][0]; int yy = y+dirKnight[j][1]; if(xx >= 0 && xx < MAX && yy >= 0 && yy < MAX) knight[i][8*xx+yy] = 1; } } } void floyd(int a[][MAX*MAX]) { for(int k = 0; k < MAX*MAX; ++k) { for(int i = 0; i < MAX*MAX; ++i) { for(int j = 0; j < MAX*MAX; ++j) { if(a[i][j] > a[i][k]+a[k][j]) a[i][j] = a[i][k]+a[k][j]; } } } } int main() { // freopen("input.txt","r",stdin); init(); floyd(king); floyd(knight); while(scanf("%s",str) != EOF) { int start = (str[0]-'A') + (str[1]-'1')*8; int num = (strlen(str)-2)/2; if(num == 0) { printf("0\n"); continue; } for(int i = 0, j = 2; i < num; ++i, j+=2) step[i] = (str[j]-'A') + (str[j+1]-'1')*8; int result = INF; int t1, t2; int sum; for(int i = 0; i < MAX*MAX; ++i) { sum = 0; for(int k = 0; k < num; ++k) sum += knight[ step[k] ][i]; for(int j = 0; j < MAX*MAX; ++j) { t1 = king[start][j]; t2 = INF; for(int kk = 0; kk < num; ++kk) { t2 = min(t2,knight[ step[kk] ][j] + knight[j][i] - knight[ step[kk] ][i]); } result = min(result,sum+t1+t2); } } printf("%d\n",result); } return 0; }