Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 941 Accepted Submission(s): 352
3 1 K.S ##1 1#T 3 1 K#T .S# 1#. 3 2 K#T .S. 21. 0 0
5 impossible 8
解题思路:
题意为一个地图,‘K‘代表孙悟空的位置,也就是起点,‘T‘代表唐僧的位置,数字‘1’‘2’等代表第几种钥匙,‘S‘代表蛇,‘#‘不能走,题意的目的就是孙悟空去救唐僧,要求前提必须是拿到给定的m种钥匙,才能去救唐僧,除了‘#‘的位置,其他位置都可以走(如果到达了唐僧的位置,但没拿到给定的m种钥匙,任务也没法完成,必须得拿到m钟钥匙),到达‘S‘位置,要多花一分钟杀死蛇,其他位置走一步花一分钟,问最少花多少分钟才能解救唐僧,如果不能,输出impossible.
题意真的不好理解:要想解救唐僧,只有唯一的方法,就是取得所有种类的钥匙,然后到达唐僧的位置,去解救。孙悟空位置和唐僧位置可以走多次。
还有蛇的状态也需要特别注意,第一次杀死蛇,第二次再到达该位置时,就不用再杀蛇了,给蛇编号,杀了为1,不杀为0,状态压缩。
定义 f[i][j][k][state] ,为坐标位置走到坐标 i, j ,时已经取得了第k种钥匙,当前蛇的状态为state。 进行广度优先搜索。
参考:http://www.cnblogs.com/whatbeg/p/3983522.html
代码:
#include <iostream> #include <algorithm> #include <string.h> #include <map> #include <queue> using namespace std; const int inf=0x3f3f3f3f; int n,m; char mp[102][102]; int dx[4]={0,0,-1,1}; int dy[4]={1,-1,0,0}; int f[102][102][12][35];//f[i][j][k][state]为坐标i,j位置处已经拿到第k种钥匙且杀死蛇的状态为state时的最小步数 int sx,sy;//开始位置 int scnt;//蛇的数量 int ans; map<pair<int,int>,int>snake;//给某一位置上的蛇编号,从1开始 struct Node { int x,y,k,s,step; }; queue<Node>q; void init() { memset(f,inf,sizeof(f)); snake.clear(); scnt=0; ans=inf; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { cin>>mp[i][j]; if(mp[i][j]=='K') sx=i,sy=j,mp[i][j]='.';//别忘了mp[i][j]='.'这一句,起始位置也可以重复多次走 else if(mp[i][j]=='S') snake[make_pair(i,j)]=++scnt;//编号 } f[sx][sy][0][0]=0; } bool ok(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=n&&mp[x][y]!='#') return true; return false; } void bfs(Node st) { if(!q.empty()) q.pop(); q.push(st); while(!q.empty()) { Node cur=q.front(); q.pop(); Node next;//下一步的状态节点 for(int i=0;i<4;i++) { int newx=cur.x+dx[i]; int newy=cur.y+dy[i]; if(!ok(newx,newy)) continue; next.x=newx,next.y=newy; if(mp[newx][newy]=='S') { int th=snake[make_pair(newx,newy)]; if(cur.s&(1<<(th-1)))//已经杀过该条蛇 { next.s=cur.s; next.k=cur.k; next.step=cur.step+1; } else { next.s=(cur.s|(1<<(th-1))); next.k=cur.k; next.step=cur.step+2; } if(next.step<f[newx][newy][next.k][next.s]) { f[newx][newy][next.k][next.s]=next.step; q.push(next); } } else if(mp[newx][newy]>='1'&&mp[newx][newy]<='9') { int th=mp[newx][newy]-'0'; if(th==cur.k+1)//当前这个钥匙正好是想要的,已有钥匙加1 next.k=cur.k+1; else next.k=cur.k; next.s=cur.s; next.step=cur.step+1; if(next.step<f[newx][newy][next.k][next.s]) { f[newx][newy][next.k][next.s]=next.step; q.push(next); } } else if(mp[newx][newy]=='.') { next.k=cur.k; next.s=cur.s; next.step=cur.step+1; if(next.step<f[newx][newy][next.k][next.s]) { f[newx][newy][next.k][next.s]=next.step; q.push(next); } } else if(mp[newx][newy]=='T') { next.k=cur.k; next.s=cur.s; next.step=cur.step+1; if(next.step<f[newx][newy][next.k][next.s]) f[newx][newy][next.k][next.s]=next.step; if(next.k==m)//该状态下不再向下扩展 ans=min(f[newx][newy][next.k][next.s],ans); else q.push(next); } } } } int main() { while(cin>>n>>m&&(n||m)) { init(); Node temp; temp.x=sx,temp.y=sy,temp.k=0,temp.s=0,temp.step=0; bfs(temp); if(ans==inf) cout<<"impossible"<<endl; else cout<<ans<<endl; } return 0; }
[ACM] HDU 5025 Saving Tang Monk (状态压缩,BFS)
原文地址:http://blog.csdn.net/sr_19930829/article/details/40352719