分析:
将一个位置和一种棋子看做一个状态。
可以给每个状态编号,用Floyd求出每两个状态间的最短路,然后按给出的顺序DP求解即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
typedef long long LL;
int n,xx[105],yy[105];
int dx[9]={0,-1,-2,-2,-1,1,2,2,1},dy[9]={0,-2,-1,1,2,2,1,-1,-2};
struct Pair{
int mov,rep;
friend Pair operator + (Pair x,Pair y){
Pair ret;
ret.mov=x.mov+y.mov;
ret.rep=x.rep+y.rep;
return ret;
}
friend bool operator < (Pair x,Pair y){
return x.mov+x.rep==y.mov+y.rep?x.rep<y.rep:x.mov+x.rep<y.mov+y.rep;
}
friend bool operator == (Pair x,Pair y){
return x.mov==y.mov&&x.rep==y.rep;
}
};
Pair dis[305][305],f[105][4];
inline int id(int x,int y,int now){
return (x-1)*n+y+n*n*(now-1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int num;scanf("%d",&num);
xx[num]=i,yy[num]=j;
}
for(int i=1;i<=n*n*3;i++)
for(int j=1;j<=n*n*3;j++)
dis[i][j].mov=dis[i][j].rep=5e8;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
for(int k=1;k<=3;k++)
for(int l=1;l<=3;l++){
if(k==l) dis[id(i,j,k)][id(i,j,l)]=(Pair){0,0};
else dis[id(i,j,k)][id(i,j,l)]=(Pair){0,1};
}
for(int k=1;k<=8;k++){
int ii=i+dx[k],jj=j+dy[k];
if(ii<=0||ii>n||jj<=0||jj>n) continue;
dis[id(i,j,1)][id(ii,jj,1)]=(Pair){1,0};
}
int ii=i-1,jj=j-1;
while(ii&&jj) dis[id(i,j,2)][id(ii--,jj--,2)]=(Pair){1,0};
ii=i+1,jj=j-1;
while(ii<=n&&jj) dis[id(i,j,2)][id(ii++,jj--,2)]=(Pair){1,0};
ii=i+1,jj=j+1;
while(ii<=n&&jj<=n) dis[id(i,j,2)][id(ii++,jj++,2)]=(Pair){1,0};
ii=i-1,jj=j+1;
while(ii&&jj<=n) dis[id(i,j,2)][id(ii--,jj++,2)]=(Pair){1,0};
ii=i-1;
while(ii) dis[id(i,j,3)][id(ii--,j,3)]=(Pair){1,0};
ii=i+1;
while(ii<=n) dis[id(i,j,3)][id(ii++,j,3)]=(Pair){1,0};
jj=j-1;
while(jj) dis[id(i,j,3)][id(i,jj--,3)]=(Pair){1,0};
jj=j+1;
while(jj<=n) dis[id(i,j,3)][id(i,jj++,3)]=(Pair){1,0};
}
for(int k=1;k<=n*n*3;k++)
for(int i=1;i<=n*n*3;i++)
for(int j=1;j<=n*n*3;j++)
dis[i][j]=std::min(dis[i][j],dis[i][k]+dis[k][j]);
for(int i=0;i<=n*n;i++)
f[i][1].mov=f[i][2].mov=f[i][3].mov=f[i][1].rep=f[i][2].rep=f[i][3].rep=5e8;
f[1][1]=f[1][2]=f[1][3]=(Pair){0,0};
for(int i=2;i<=n*n;i++)
for(int j=1;j<=3;j++){
int now=id(xx[i],yy[i],j);
for(int k=1;k<=3;k++){
int pre=id(xx[i-1],yy[i-1],k);
f[i][j]=std::min(f[i][j],f[i-1][k]+dis[pre][now]);
}
}
Pair ans=std::min(f[n*n][1],std::min(f[n*n][2],f[n*n][3]));
printf("%d %d\n",ans.mov+ans.rep,ans.rep);
return 0;
}