題目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=361
BFS。。ZOJ的資料相對poj水了點,直接BFS。就可以過了、這題關鍵是判重,把蛇頭座標和蛇身相對座標表示出來。。在擷取蛇身的相對座標時搞錯了。導致錯了N次。
計算蛇身時,要把蛇頭去掉。也就是l-1,= =!
對於poj的資料,我用的a*過的。。稍微加了一下最佳化。。評估函數為當前步數加上蛇頭到(1,1)的至少應該走的步數。 (單獨) 蛇頭到(1,1)的至少應走的步數的計算,也就是不計算蛇身的位置。那麼直接BFS就可以了。
如果還加上蛇身。效率應該更快。但是我這樣寫簡便一點。
下面是沒最佳化的代碼:
#include<cstdio>#include<queue>#include<cstring>#include<cstdlib>using namespace std;const int maxn =21;int n,m,l,find,ans,move;bool map[maxn][maxn];int dx[]={1,-1,0,0};int dy[]={0,0,1,-1};bool vis[maxn][maxn][1<<14];bool check(int x,int y){ return x>=1&&x<=n&&y>=1&&y<=m; }struct node{ int head[2],tail[2]; bool map[maxn][maxn]; int step,val;}s_pos;void bfs(){ memset(vis,false,sizeof(vis)); queue<node > q; q.push(s_pos); vis[s_pos.head[0]][s_pos.head[1]][ s_pos.val] =true; while(!q.empty()){ node now = q.front(); q.pop(); if(now.head[0]==1&&now.head[1]==1){ find=1; ans=now.step; return ; } for(int i=0;i<4;i++){ node next = now; next.step+=1; int x=now.head[0]+dx[i]; int y=now.head[1]+dy[i]; if(check(x,y)){ if(next.map[x][y]) continue; next.head[0]=x; next.head[1]=y; next.map[x][y]=true; next.map[now.tail[0]][now.tail[1]]=false; int t= next.val&3; next.tail[0]=now.tail[0]+dx[t]; next.tail[1]=now.tail[1]+dy[t]; next.val=next.val>>2; int sum=i<<move; next.val+=sum; if(!vis[x][y][next.val]){ vis[x][y][next.val]=true; q.push(next); } } } }}int main(){ int t,x,y,ca=1; int nx[10],ny[10]; while(scanf("%d%d%d",&n,&m,&l)!=EOF,(n+m+l)){ memset(s_pos.map,false,sizeof(s_pos.map)); memset(map,false,sizeof(map)); s_pos.val=0; move=((l<<1)-4); for(int i=0;i<l;i++) { scanf("%d%d",&x,&y); nx[i]=x;ny[i]=y; s_pos.map[x][y]=true; if(i>0){ for(int j=0;j<4;j++){ if(x+dx[j]==nx[i-1]&&y+dy[j]==ny[i-1]){ s_pos.val=(s_pos.val<<2)+j; break; } } } } s_pos.head[0]=nx[0], s_pos.head[1]=ny[0]; s_pos.tail[0]=nx[l-1];s_pos.tail[1]=ny[l-1]; scanf("%d",&t); s_pos.step=0; for(int i=0;i<t;i++){ scanf("%d%d",&x,&y); map[x][y]=true; s_pos.map[x][y]=true; } find=0; bfs(); printf("Case %d: ",ca++); if(find){ printf("%d\n",ans); } else printf("-1\n"); } return 0;}
下面是最佳化的代碼:
#include<cstdio>#include<queue>#include<cstring>#include<cstdlib>using namespace std;const int maxn =21;int n,m,l,fond,ans,move,ca;bool map[maxn][maxn];int cnt[maxn][maxn];int dx[]={1,-1,0,0};int dy[]={0,0,1,-1};unsigned char vis[maxn][maxn][1<<14];inline bool check(int x,int y){ return x>=1&&x<=n&&y>=1&&y<=m; }struct node{ int head[2],tail[2]; bool map[maxn][maxn]; int step,val; bool operator <(const node &a) const{ return cnt[a.head[0]][a.head[1]]+a.step<cnt[head[0]][head[1]]+step; }}s_pos;void get_min(){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt[i][j]=1000000; cnt[1][1]=0; queue<int > q;q.push(1); q.push(1); while(!q.empty()){ int x=q.front(); q.pop();int y=q.front();q.pop(); for(int i=0;i<n;i++){ int nx=x+dx[i]; int ny=y+dy[i]; if(check(nx,ny)){ if(map[nx][ny]) continue ; if(cnt[x][y]+1<cnt[nx][ny]){ cnt[nx][ny]=cnt[x][y]+1; q.push(nx); q.push(ny); } } } }}void bfs(){ priority_queue<node > q; q.push(s_pos); vis[s_pos.head[0]][s_pos.head[1]][ s_pos.val] =true; while(!q.empty()){ node now = q.top(); q.pop(); if(now.head[0]==1&&now.head[1]==1){ fond=1; ans=now.step; return ; } for(int i=0;i<4;i++){ node next = now; next.step+=1; int x=now.head[0]+dx[i]; int y=now.head[1]+dy[i]; if(check(x,y)){ if(next.map[x][y]) continue; next.head[0]=x; next.head[1]=y; next.map[x][y]=true; next.map[now.tail[0]][now.tail[1]]=false; int t= next.val&3; next.tail[0]=now.tail[0]+dx[t]; next.tail[1]=now.tail[1]+dy[t]; next.val=next.val>>2; int sum=i<<move; next.val+=sum; if(vis[x][y][next.val]!=ca){ vis[x][y][next.val]=ca; q.push(next); } } } }}int main(){ int t,x,y; int nx[10],ny[10]; ca=1; while(scanf("%d%d%d",&n,&m,&l)!=EOF,(n+m+l)){ memset(s_pos.map,false,sizeof(s_pos.map)); memset(map,false,sizeof(map)); s_pos.val=0; move=((l<<1)-4); for(int i=0;i<l;i++) { scanf("%d%d",&x,&y); nx[i]=x;ny[i]=y; s_pos.map[x][y]=true; if(i>0){ for(int j=0;j<4;j++){ if(x+dx[j]==nx[i-1]&&y+dy[j]==ny[i-1]){ s_pos.val=(s_pos.val<<2)+j; break; } } } } s_pos.head[0]=nx[0], s_pos.head[1]=ny[0]; s_pos.tail[0]=nx[l-1];s_pos.tail[1]=ny[l-1]; scanf("%d",&t); s_pos.step=0; for(int i=0;i<t;i++){ scanf("%d%d",&x,&y); map[x][y]=true; s_pos.map[x][y]=true; } fond=0; get_min(); bfs(); printf("Case %d: ",ca++); if(fond){ printf("%d\n",ans); } else printf("-1\n"); } return 0;}