CF1065D Three Pieces (多元最短路)

题目大意:给你一个棋盘,你需要控制棋子依次经过编号为1~n的所有点,棋子的可以是车,马,象,都依照国际象棋的行棋方式,每走一步消耗1单位时间,但每次更换棋子都需要额外1单位时间,求经过所有点需要的最少时间 ,如果多种方案需要的最少时间相同,输出更换棋子次数最少的那个

有的机房老人用了记忆化搜索,但写起来好像很蛋疼。神仙学弟phy想了一个多元最短路,简洁好写

每个点有三种状态,先暴力建边。

然后根据点的编号从小到大,以每个点为源点跑一次两元最短路

注意,不能在个点都记录超级源点/汇点,因为这样做会让更换棋子的步骤失效!

所以,每当跑完某个点的最短路时,先记录当前下一个点的三种状态的花费,从下一个编号的点开始跑时,先清数组,再把上次记录的花费扔到起始状态里,再去跑这个点为源点的最短路
接下来就是多元最短路了,可以用重载运算符,比较好写

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N 15
  6 #define M 500
  7 #define inf 66666666
  8 using namespace std;
  9 
 10 int n,cte,num;
 11 int mp[N][N],id[N][N][4],head[M];
 12 int px[M],py[M];
 13 struct node{int d,w;
 14     friend bool operator < (const node &s1,const node &s2){
 15         if(s1.d!=s2.d) return s1.d<s2.d;
 16         else return s1.w<s2.w;
 17     }node(int d,int w):d(d),w(w){} node(){}
 18 };
 19 struct Edge{int to,nxt,d,w;}edge[M*50];
 20 void ae(int u,int v,int d,int w){
 21     cte++;edge[cte].to=v,edge[cte].nxt=head[u];
 22     edge[cte].d=d,edge[cte].w=w,head[u]=cte;
 23 }
 24 inline int check(int x,int y)
 25 {return 1<=x&&x<=n&&1<=y&&y<=n;}
 26 void Build_Edge()
 27 {
 28     int s0,s1,s2,s3,t1,t2,t3;
 29     for(int i=1;i<=n;i++)
 30         for(int j=1;j<=n;j++){
 31             s1=id[i][j][1],s2=id[i][j][2],s3=id[i][j][3];
 32             ae(s1,s2,1,1),ae(s2,s1,1,1),ae(s1,s3,1,1),ae(s3,s1,1,1),ae(s2,s3,1,1),ae(s3,s2,1,1);
 33             for(int x=1;x<=n;x++){if(!check(i+x,j))break;t1=id[i+x][j][1],ae(s1,t1,1,0);}
 34             for(int x=1;x<=n;x++){if(!check(i,j+x))break;t1=id[i][j+x][1],ae(s1,t1,1,0);}
 35             for(int x=1;x<=n;x++){if(!check(i-x,j))break;t1=id[i-x][j][1],ae(s1,t1,1,0);}
 36             for(int x=1;x<=n;x++){if(!check(i,j-x))break;t1=id[i][j-x][1],ae(s1,t1,1,0);}
 37             
 38             for(int x=1;x<=n;x++){if(!check(i+x,j+x))break;t3=id[i+x][j+x][3],ae(s3,t3,1,0);}
 39             for(int x=1;x<=n;x++){if(!check(i-x,j+x))break;t3=id[i-x][j+x][3],ae(s3,t3,1,0);}
 40             for(int x=1;x<=n;x++){if(!check(i+x,j-x))break;t3=id[i+x][j-x][3],ae(s3,t3,1,0);}
 41             for(int x=1;x<=n;x++){if(!check(i-x,j-x))break;t3=id[i-x][j-x][3],ae(s3,t3,1,0);}
 42             
 43             if(check(i+1,j+2))t2=id[i+1][j+2][2],ae(s2,t2,1,0);
 44             if(check(i+2,j+1))t2=id[i+2][j+1][2],ae(s2,t2,1,0);
 45             if(check(i-1,j-2))t2=id[i-1][j-2][2],ae(s2,t2,1,0);
 46             if(check(i-2,j-1))t2=id[i-2][j-1][2],ae(s2,t2,1,0);
 47             if(check(i+1,j-2))t2=id[i+1][j-2][2],ae(s2,t2,1,0);
 48             if(check(i+2,j-1))t2=id[i+2][j-1][2],ae(s2,t2,1,0);
 49             if(check(i-1,j+2))t2=id[i-1][j+2][2],ae(s2,t2,1,0);
 50             if(check(i-2,j+1))t2=id[i-2][j+1][2],ae(s2,t2,1,0);
 51         }
 52 
 53 }
 54 node dis[M],lst[5];int use[M];
 55 node SPFA()
 56 {
 57     int s1,s2,s3,t1,t2,t3;
 58     queue<int>q;node tmp;
 59     for(int i=1;i<n*n;i++)
 60     {
 61         memset(dis,0x3f,sizeof(dis));
 62         memset(use,0,sizeof(use));
 63         s1=id[px[i]][py[i]][1];
 64         s2=id[px[i]][py[i]][2];
 65         s3=id[px[i]][py[i]][3];
 66         dis[s1]=lst[1],dis[s2]=lst[2],dis[s3]=lst[3];
 67         use[s1]=1,use[s2]=1,use[s3]=1;
 68         q.push(s1),q.push(s2),q.push(s3);
 69         while(!q.empty())
 70         {
 71             int x=q.front();q.pop();
 72             tmp=dis[x];
 73             for(int j=head[x];j;j=edge[j].nxt){
 74                 int v=edge[j].to;
 75                 tmp.d+=edge[j].d,tmp.w+=edge[j].w;
 76                 if(tmp<dis[v]){ dis[v]=tmp;
 77                     if(!use[v]) use[v]=1,q.push(v);
 78                 }tmp=dis[x];
 79             }use[x]=0;
 80         }
 81         t1=id[px[i+1]][py[i+1]][1];
 82         t2=id[px[i+1]][py[i+1]][2];
 83         t3=id[px[i+1]][py[i+1]][3];
 84         lst[1]=dis[t1],lst[2]=dis[t2],lst[3]=dis[t3];
 85     }
 86     node ret;ret.d=inf,ret.w=inf;
 87     s1=id[px[n*n]][py[n*n]][1];
 88     s2=id[px[n*n]][py[n*n]][2];
 89     s3=id[px[n*n]][py[n*n]][3];
 90     if(dis[s1]<ret) ret=dis[s1];
 91     if(dis[s2]<ret) ret=dis[s2];
 92     if(dis[s3]<ret) ret=dis[s3];
 93     return ret;
 94 }
 95 
 96 int main()
 97 {
 98     //freopen("t1.in","r",stdin);
 99     scanf("%d",&n);
100     for(int i=1;i<=n;i++)
101         for(int j=1;j<=n;j++)
102             scanf("%d",&mp[i][j]),id[i][j][1]=++num,id[i][j][2]=++num,
103             id[i][j][3]=++num,px[mp[i][j]]=i,py[mp[i][j]]=j;
104     Build_Edge();
105     node ret=SPFA();
106     printf("%d %d
",ret.d,ret.w);
107     return 0;
108 }
原文地址:https://www.cnblogs.com/guapisolo/p/9894352.html