[CF1065D]Three Pieces:最短路+DP

分析:

将一个位置和一种棋子看做一个状态。
可以给每个状态编号,用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;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9783592.html