2016年ACM/ICPC北京賽區 E題(bfs)
阿新 • • 發佈:2018-11-11
題意:一個長度為5的串,初始為12345,有三種變化方式:
1、交換任意相鄰的兩個數,無次數限制
2、任意一位上的數字加1,超過10對10取模,限制3次。
3、任意一位上的數字*2,超過10對10取模,限制2次。
現在給你一個串,求12345變成這個串的最小次數。如果無法變成,則輸出-1。
思路:
經典bfs,開三維記錄一下12345變成數i、用j次2操作、k次3操作的最小次數,然後記憶一下就可以O(1)查詢了。
程式碼:
#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f using namespace std; int n,m,k; int go; int vis[100010][4][3]; bool us[100010]; int jc[10]; void bfs() { memset(us,0,sizeof(us)); jc[6]=1; for(int i=5;i>=0;i--) jc[i]=jc[i+1]*10; for(int i=0;i<=99999;i++) for(int j=0;j<4;j++) for(int k=0;k<3;k++) vis[i][j][k]=inf; queue<int>q; q.push(12345); us[12345]=1; vis[12345][0][0]=0; while(!q.empty()) { //cout<<"*"; int a=q.front();q.pop(); us[a]=0; for(int i=1;i<5;i++) { int j=i+1; int x=(a%jc[i])/jc[i+1]; int y=(a%jc[j])/jc[j+1]; //cout<<x<<y<<endl; if(x==y) continue; int tmp=a-x*jc[i+1]-y*jc[j+1]; tmp+=x*jc[j+1]+y*jc[i+1]; //cout<<a<<" "<<tmp<<endl; int fg=0; for(int k=0;k<4;k++) for(int l=0;l<3;l++) { if(vis[tmp][k][l]>vis[a][k][l]+1) { vis[tmp][k][l]=vis[a][k][l]+1; fg=1; } } if(fg&&!us[tmp]) { us[tmp]=1; q.push(tmp); } } for(int i=1;i<6;i++) { int x=(a%jc[i])/jc[i+1]; int tmp=a-x*jc[i+1]+((x+1)%10)*jc[i+1]; if(tmp==a) continue; int fg=0; for(int k=1;k<4;k++) for(int l=0;l<3;l++) if(vis[tmp][k][l]>vis[a][k-1][l]+1) { vis[tmp][k][l]=vis[a][k-1][l]+1; fg=1; } if(fg&&!us[tmp]) { us[tmp]=1; q.push(tmp); } } for(int i=1;i<6;i++) { int x=(a%jc[i])/jc[i+1]; int tmp=a-x*jc[i+1]+((x*2)%10)*jc[i+1]; if(tmp==a) continue; int fg=0; for(int k=0;k<4;k++) for(int l=1;l<3;l++) if(vis[tmp][k][l]>vis[a][k][l-1]+1) { vis[tmp][k][l]=vis[a][k][l-1]+1; fg=1; } if(fg&&!us[tmp]) { us[tmp]=1; q.push(tmp); } } } } int main() { bfs(); int x; while(scanf("%d",&x)!=EOF) { int ma=inf; for(int i=0;i<4;i++) for(int j=0;j<3;j++) ma=min(ma,vis[x][i][j]); if(ma==inf) puts("-1"); else printf("%d\n",ma); } return 0; }