codeforces_1065_D.three pieces_思维
Posted jasonlixuetao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces_1065_D.three pieces_思维相关的知识,希望对你有一定的参考价值。
题意:一个正方形棋盘,三种棋子,knight:像中国象棋中的马一样走;bishop:斜着走;rook:中国象棋中的车。棋盘中每个格子中标着1--n*n的互不相同的数字,从1开始任选一种棋子开始走,在每个格子,要么移动棋子,要么更换一种棋子,每个格子可以重复走,移动或更换都算作一步。问从1按增序走到n*n,至少需要多少步,相同步数情况下选择替换次数最少的方案。
思路:这道题的难点在于每一步可以更换棋子,算上棋子种类,一共3维[i][j][p],每走一步是从[i][j][p]走到[i‘][j‘][p‘],在这种情况下问题有点复杂。但是可以发现任何一点到另一点最多可以3步走到,bishop和rook这两种非常容易算出步数,然后再通过dfs搜索一下knight需要的步数,每走一步验证三种情况,感觉应该可以,改天试试。
另一种思路,官方题解的思路。为了化简问题,将[i][j][k]当做一种状态,用i*n*3+j*3+k映射为一个整数,由此可以构建状态的邻接矩阵,再使用最短路算法求出每个状态之间的最短路,最后按顺序dp一下。这个方法比较巧妙,将3维的状态映射到1维上,值得思考。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define LL long long #define N 12 int n; int getState(int x,int y,int p) { return x*n*3+y*3+p; } struct Pair { int mov,rep; Pair() {} Pair(int m,int r) { mov=m; rep=r; } bool operator < (const Pair t)const { if(mov+rep==t.mov+t.rep) return rep<t.rep; else return mov+rep<t.mov+t.rep; } Pair operator + (const Pair t)const { Pair ret; ret.mov=mov+t.mov; ret.rep=rep+t.rep; return ret; } int sum() { return mov+rep; } }; int dx[8]= {-2,-2,-1,1,2,2,1,-1}; //knight int dy[8]= {-1,1,2,2,1,-1,-2,-2}; Pair gra[N*N*3][N*N*3]; void buildGra() { for(int i=0; i<n*n*3; i++) for(int j=0; j<n*n*3; j++) gra[i][j]=Pair(1000,1000); for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { for(int k=0; k<3; k++) for(int l=0; l<3; l++) { int t1=getState(i,j,k); int t2=getState(i,j,l); //cout<<"*"<<t1<<" "<<t2<<endl; if(t1==t2) gra[t1][t1]=Pair(0,0); else gra[t1][t2]=gra[t2][t1]=Pair(0,1); } for(int k=0; k<8; k++) //knight { int xx=i+dx[k]; int yy=j+dy[k]; if(xx>=0&&xx<n&&yy>=0&&yy<n) { int t1=getState(i,j,0); int t2=getState(xx,yy,0); gra[t1][t2]=gra[t2][t1]=Pair(1,0); } } for(int k=-1; k<=1; k++) //bishop for(int l=-1; l<=1; l++) { if(k==0||l==0) continue; int xx=i+k; int yy=j+l; while(xx>=0&&xx<n&&yy>=0&&yy<n) { int t1=getState(i,j,1); int t2=getState(xx,yy,1); gra[t1][t2]=gra[t2][t1]=Pair(1,0); xx+=k; yy+=l; } } for(int k=i+1; k<n; k++) //rook { int t1=getState(i,j,2); int t2=getState(k,j,2); gra[t1][t2]=gra[t2][t1]=Pair(1,0); } for(int k=j+1; k<n; k++) { int t1=getState(i,j,2); int t2=getState(i,k,2); gra[t1][t2]=gra[t2][t1]=Pair(1,0); } } } } int main() { int R[105],C[105]; scanf("%d",&n); for(int i=0; i<n; i++) for(int j=0; j<n; j++) { int num; scanf("%d",&num); R[num]=i; C[num]=j; } buildGra(); for(int k=0; k<n*n*3; k++) for(int i=0; i<n*n*3; i++) for(int j=0; j<n*n*3; j++) if(gra[i][k]+gra[k][j]<gra[i][j]) gra[i][j]=gra[i][k]+gra[k][j]; Pair dp[N*N][3]; dp[1][0]=dp[1][1]=dp[1][2]=Pair(0,0); for(int i=2; i<=n*n; i++) { dp[i][0]=dp[i][1]=dp[i][2]=Pair(1000,1000); int xx=R[i],yy=C[i]; for(int j=0; j<3; j++) { for(int k=0; k<3; k++) { int snow=getState(xx,yy,j); int slst=getState(R[i-1],C[i-1],k); if(dp[i-1][k]+gra[slst][snow]<dp[i][j]) dp[i][j]=dp[i-1][k]+gra[slst][snow]; } } } Pair res(1000,1000); for(int i=0; i<3; i++) if(dp[n*n][i]<res) res=dp[n*n][i]; printf("%d %d ",res.sum(),res.rep); return 0; }
以上是关于codeforces_1065_D.three pieces_思维的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #726 (Div. 2) B. Bad Boy(贪心)