D. Three Pieces(dp,array用法,棋盤模型)
阿新 • • 發佈:2018-11-10
https://codeforces.com/contest/1065/problem/D
題意
給你一個方陣,裡面的數字從1~nn,你需要從標號為1的格子依次走到標號為nn,在每一個格子你有兩個決策:
1.換工具(車,馬,象)
2.不換工具,繼續走
換工具本身算作一步,問最少需要多少步才能完成目標,要是步數相同,需要換工具步數最小
思路
思路十分明確,每個格子有三個狀態,處理出每個格子每個狀態之間的最小步,然後從編號為1的格子進行dp,答案就是
min(dp[id[n]][0~2])
處理
這道題難在處理
怎麼保證狀態編號唯一
首先將二維座標一維化,因為每個位置有三種狀態等於加了一維上去,所以要將一維化的座標*3,再加上0~2,每一個格子每一種狀態就形成唯一的編號
怎麼處理車,馬,象
車:i==p||j==q
馬: abs(i-p)+abs(j-q)==3
象:i+j==p+q||i-j==p-q
需要注意的是,一定要用if else if 並且注意判斷順序(先判車後判馬),因為對於車的判定有的馬會在裡面,所以必須得先把車給判掉關於答案的計算
學了一下array,可以直接比較(按下標逐個比),可以過載運算子
還有memset可以初始化結構體,1大概是1e7
#include<bits/stdc++.h> #define inf 0x3f3f3f3f #define M 505 using namespace std; array<int,2> f[M][M],dp[M][5],ans; int n,i,j,k,a[M],p,q,x,y; int id(int x,int y){return (x*n+y)*3;} array<int,2> operator+(const array<int,2> a,const array<int,2> b){ return {a[0]+b[0],a[1]+b[1]}; } int main(){ cin>>n; for(i=0;i<n*n;i++){cin>>x;a[x]=i;} memset(f,1,sizeof(f));memset(dp,1,sizeof(dp)); for(i=0;i<n;i++){ for(j=0;j<n;j++){ for(p=0;p<3;p++)for(q=0;q<3;q++){ x=id(i,j); f[x+p][x+q]={1,1}; } for(p=0;p<n;p++){ for(q=0;q<n;q++){ x=id(i,j);y=id(p,q); if(p==i||q==j)f[x][y]={1,0}; else if(abs(i-p)+abs(j-q)==3)f[x+1][y+1]={1,0}; else if(p+q==i+j||p-q==i-j)f[x+2][y+2]={1,0}; } } } } for(k=0;k<3*n*n;k++)for(i=0;i<3*n*n;i++)for(j=0;j<3*n*n;j++)f[i][j]=min(f[i][j],f[i][k]+f[k][j]); dp[1][0]=dp[1][1]=dp[1][2]={0,0}; for(i=2;i<=n*n;i++){ q=a[i]*3;p=a[i-1]*3; for(j=0;j<3;j++) for(k=0;k<3;k++) dp[i][j]=min(dp[i][j],dp[i-1][k]+f[p+k][q+j]); } ans=min(dp[n*n][0],min(dp[n*n][1],dp[n*n][2])); cout<<ans[0]<<" "<<ans[1]; }