先给一个我最先写的一个代码吧。总体思路是这样的,对于每个输入的点,都进行一次广搜,打出到达其他点的最短路径(这个效率相比于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;
}