1. 程式人生 > >The Morning after Halloween uva1601

The Morning after Halloween uva1601

getchar() 字母 都是 應該 its 右移 size per 進行

這題可以用普通bfs來做 也可以用雙向bfs來做(先欠著)

有點類似專題訓練的一題 不過那題是找鑰匙開門 不過都用了狀態壓縮

題意: n,m(<=16) 的網絡上有t(<=3)小寫字母 並且網絡上有其大寫字母 要求最少的步使得所有小寫字母到大寫字母裏面去 每步可以多個小寫字母同時移動(上下左右加不動) 移動後任意兩個小寫字母不能占用同一個位置 也不能在一步之內進行交換位置

且任何一個2*2子網絡中至少有一個障礙格

分析: 小寫字母最多三個 已經算是少的了 但是有十六乘十六網絡 當有三個小寫字母的時候 狀態總數為 256的三次方 每次狀態轉移有 5的三次方枚舉量 普通bfs肯定是超時的

題目已經暗示了大部分格子都是障礙 因此應該把所有的狀態列出來 形成一張圖 而不是臨時判斷五種方案是否合理

過程:先是給所有有效格標號 儲存 然後枚舉所有的狀態 (我現在還是不懂這有什麽區別 一個是在main裏面判斷地圖 一個是在bfs裏面判斷地圖 總的枚舉量也沒有減少?)

然後狀態壓縮就十分巧妙了 因為格子最多標號為 十六乘十六等於二百五十六 為0xff 為2的八次方 所以左移八位 要得到改狀態時右移 取&0xff

還有就是當字母不滿三個的時候 加至三個 方便處理 因為狀態壓縮的相關都是以三個為基準的

看到bfs先判斷枚舉量 因為這種bfs和我之前做的普通bfs不同 標記數組狀態很多 所以要謹慎

#include<bits/stdc++.h>
using namespace std;
#define N 150
int dis[N];
int n,m,t;
char mp[N][N];
int id[N][N];
int x[N];
int y[N];
int s[4];
int e[4];
int G[N][N];
int vis[N][N][N];
int dx[5]={0,0,0,1,-1};
int dy[5]={0,1,-1,0,0};
bool judge(int x,int x1,int y,int y1)
{
    if(x1==y1||(x==y1&&x1==y)  )
     
return 0; return 1; } int id1(int a,int b,int c) { return (a<<16)|(b<<8)|c; } bool inmap(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=m) return 1; return 0; } int bfs() { memset(vis,-1,sizeof( vis)); queue<int>q; q.push( id1(s[0],s[1],s[2]) ); vis[s[0]][s[1] ][s[2] ]=0; while(!q.empty()) { int u=q.front();q.pop(); int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u&0xff; printf("%d %d %d\n",a,b,c); if(a==e[0]&&b==e[1]&&c==e[2])return vis[a][b][c]; for(int i=0;i<dis[a];i++) { int a2=G[a][i]; for(int j=0;j<dis[b];j++) { int b2=G[b][j]; if(!judge(a,a2,b,b2))continue; for(int k=0;k<dis[c];k++) { int c2=G[c][k]; if(!judge(a,a2,c,c2))continue; if(!judge(b,b2,c,c2))continue; if(vis[a2][b2][c2]!=-1)continue; vis[a2][b2][c2]=vis[a][b][c]+1; q.push( id1(a2,b2,c2) ); } } } } return -1; } int main() { while(scanf("%d%d%d",&m,&n,&t)&&t) { getchar(); for(int i=0;i<n;i++) fgets(mp[i],100,stdin); int cnt=0;int goal=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(mp[i][j]!=#) { id[i][j]=cnt; x[cnt]=i;y[cnt]=j; if(islower(mp[i][j])){s[ mp[i][j]-a ]=cnt; } if(isupper(mp[i][j])){e[ mp[i][j]-A ]=cnt; } cnt++; } printf("%d %d %d\n",s[0],s[1],s[2]); printf("%d %d %d\n",e[0],e[1],e[2]); for(int i=0;i<cnt;i++) { dis[i]=0; for(int k=0;k<5;k++) { int nx=x[i]+dx[k]; int ny=y[i]+dy[k]; if(inmap(nx,ny)&&mp[nx][ny]!=#)G[i][dis[i]++ ]=id[nx][ny]; } } if(t<=2){dis[cnt]=1;G[cnt][0]=cnt;s[2]=e[2]=cnt++;} if(t<=1){dis[cnt]=1;G[cnt][0]=cnt;s[1]=e[1]=cnt++;} printf("%d\n",bfs()); } return 0; }

The Morning after Halloween uva1601