利用一个dis数组表示骑士从点(i,j)到点(x,y)的最短距离,预处理这个数组,用bfs将floyd算法简化为O(N^2),然后对于每一点枚举所有骑士走到此处的最短距离和,在枚举每个骑士接国王所需最短路径,注意判断此点骑士是否可达,其最小值即可。
/*
ID: jinusac1
PROG: camelot
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
typedef struct Position{
int x,y;
}Pos;
struct KING{
int x,y;
int cost;
}king[25];
int sizek=1;
int dis[27][31][27][31]={0},size1=0,R1,C;
int dir[8][2]={2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2};
int one[8][2]={1,1,1,-1,-1,1,-1,-1,1,0,-1,0,0,1,0,-1};
int two[16][2]={2,0,-2,0,0,2,0,-2,2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2,2,2,2,-2,-2,2,-2,-2};
Pos pos[800];
inline bool is(int x,int y)
{
if(x<=0||x>R1||y<=0||y>C) return 0;
return 1;
}
void bfs(int sx,int sy)
{
bool have[27][31]={false};
Pos t;
t.x=sx;
t.y=sy;
have[sx][sy]=true;
queue<Pos> h;
h.push(t);
while(!h.empty()){
int tx=h.front().x,ty=h.front().y;
h.pop();
for(int i=0;i<8;i++){
int rx=tx+dir[i][0],ry=ty+dir[i][1];
if(is(rx,ry)&&!have[rx][ry]){
have[rx][ry]=true;
dis[sx][sy][rx][ry]=dis[sx][sy][tx][ty]+1;
t.x=rx;t.y=ry;
h.push(t);
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
freopen("camelot.in","r",stdin);
freopen("camelot.out","w",stdout);
cin>>C>>R1;
char t;
int kx,ky;
cin>>t>>ky;
kx=t-'A'+1;
int tx,ty;
while(cin>>t>>ty){
if(t=='!') break;
tx=t-'A'+1;
pos[size1].x=tx;
pos[size1].y=ty;
int tttt=size1;
size1++;
}
for(int i=1;i<=R1;i++)
for(int j=1;j<=C;j++) bfs(i,j);
king[0].cost=0;king[0].x=kx;king[0].y=ky;
for(int i=0;i<8;i++) if(is(kx+one[i][0],ky+one[i][1])){
king[sizek].cost=1;
king[sizek].x=kx+one[i][0];
king[sizek].y=ky+one[i][1];
sizek++;
}
for(int i=0;i<16;i++) if(is(kx+two[i][0],ky+two[i][1])){
king[sizek].cost=2;
king[sizek].x=kx+two[i][0];
king[sizek].y=ky+two[i][1];
sizek++;
}
int ans=0x7FFFFFFF;
for(int x=1;x<=R1;x++)
for(int y=1;y<=C;y++){
int sum=0;
bool mark=true;
for(int i=0;i<size1;i++){
if((x!=pos[i].x||y!=pos[i].y)&&!dis[pos[i].x][pos[i].y][x][y]){
mark=false;
break;
}
sum+=dis[pos[i].x][pos[i].y][x][y];
}
if(!mark) continue;
if((abs(x-kx)+abs(y-ky)+sum)<ans) ans=abs(x-kx)+abs(y-ky)+sum;
for(int i=0;i<size1;i++){
int temp1=sum-dis[pos[i].x][pos[i].y][x][y];
for(int j=0;j<sizek;j++) {
if((king[j].x!=pos[i].x||king[j].y!=pos[i].y)&&!dis[pos[i].x][pos[i].y][king[j].x][king[j].y])
continue;
int temp2=temp1+dis[pos[i].x][pos[i].y][king[j].x][king[j].y];
temp2+=dis[king[j].x][king[j].y][x][y];
temp2+=king[j].cost;
if(temp2<ans) ans=temp2;
}
}
}
cout<<ans<<endl;
return 0;
}