1我们预处理一个数组dist[i][j][p][q]表示骑士从(i,j)到(p,q)要走的最短步数(直接用bfs即可)
2我们枚举每个点作为汇合点
3对于每个点第一种情况是,骑士不接国王走过去,国王自己走过去。第二种情况是有个骑士走过去接国王。
4第一种情况直接无脑加dist就行,对于第二种情况枚举每个骑士去接国王然后到汇合点所用步数,去最小值就行啦。
#include<iostream> #include<queue> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define inf 0x3f3f3f3f struct node{int r,c;}king,knight[1009]; queue<node> qu; char ch[11]; int dist[51][51][51][51],visit[1009][1009], dx[8]={1,2,2,1,-1,-2,-2,-1}, dy[8]={2,1,-1,-2,-2,-1,1,2}; int n,m,tot=0,ans=inf; bool check(int x,int y){return (x>0&&x<=n&&y>0&&y<=m);} void bfs(int p,int q) { memset(visit,0,sizeof(visit));visit[p][q]=1;dist[p][q][p][q]=0;qu.push((node){p,q}); while(!qu.empty()) { node k=qu.front();qu.pop(); int step=dist[p][q][k.r][k.c]; for (int i=0;i<8;i++) { int x=k.r+dx[i],y=k.c+dy[i]; if (check(x,y)&&!visit[x][y]) { visit[x][y]=1; dist[p][q][x][y]=step+1; qu.push((node){x,y}); } } } } void init(){for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)for (int p=1;p<=n;p++)for (int q=1;q<=m;q++) dist[i][j][p][q]=inf;} int main() { scanf("%d%d",&n,&m); scanf("%s%d",&ch,&king.r);king.c=ch[0]-'A'+1; while(~scanf("%s%d",&ch,&knight[++tot].r)) knight[tot].c=ch[0]-'A'+1; init(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) bfs(i,j); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int res=0;bool f=true; for (int k=1;k<=tot;k++) if (dist[knight[k].r][knight[k].c][i][j]!=inf) res+=dist[knight[k].r][knight[k].c][i][j];else {f=false;break;} if (!f) continue; ans=min(ans,res+max(abs(king.r-i),abs(king.c-j))); for (int k=1;k<=tot;k++) { int temp=res-dist[knight[k].r][knight[k].c][i][j]; if (temp>=ans) continue; for (int x=king.r-2;x<=king.r+2;x++) for (int y=king.c-2;y<=king.c+2;y++) if (check(x,y))ans=min(ans,temp+dist[x][y][i][j]+dist[x][y][knight[k].r][knight[k].c]+max(abs(king.r-x),abs(king.c-y))); } } printf("%d\n",ans); return 0; }