Kaitou Kid - The Phantom Thief (2)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 762 Accepted Submission(s): 255
Problem Description
破解字迷之后,你得知Kid将会在展览开始后T分钟内盗取至少一颗宝石,并离开展馆。整个展馆呈矩形分布,划分为N*M个区域,有唯一的入口和出口(不能从出口进入,同样不能从入口出去)。由某个区域可直接移动至相邻四个区域中的一个,且最快需要一分钟。假设Kid进入放有宝石的区域即可盗取宝石,无需耗时。问至少要封锁几个区域(可以封锁放有宝石的区域,但不能封锁入口和出口)才能保证Kid无法完成任务。
Input
输入的第一行有一个整数C,代表有C组测试数据。每组测试数据的第一行有三个整数N,M,T(2<=N,M<=8,T>0)。接下来N行M列为展馆布置图,其中包括:
'S':入口
'E':出口
'J':放有宝石的区域,至少出现一次
'.':空白区域
'#':墙
'S':入口
'E':出口
'J':放有宝石的区域,至少出现一次
'.':空白区域
'#':墙
Output
对每组测试数据,输出至少要封锁的区域数。
Sample Input
2 5 5 5 SJJJJ ..##J .JJJJ .J... EJ... 5 5 6 SJJJJ ..##J .JJJJ .J... EJ...
Sample Output
0 2思路:因为可以封锁入口或出口周围的四个点,所以答案不能超过四。我们可以在kid成功完成任务的路径上尝试封锁某个点,然后dfs,在dfs中用bfs判断能不能保证kid失败,若不能,则再封锁一个点,继续dfs和bfs。dfs的层数不会超过四。若能够保证kid失败,则取封锁点最少的方案,若封锁点大于4,则舍去。AC代码:#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cmath> #include <string> #include <algorithm> #define INF 10000000 using namespace std; struct node { int x,y; int step; //表示时间 int num; //表示是否拿到宝石 int rox[70]; //保存到达该点的路径 int roy[70]; } start; int d[4][2]= {{1,0},{-1,0},{0,1},{0,-1}}; int m,n,T,ans; char map[105][105]; bool v[10][10][2]; 三维数组,第三维表示该点是否已拿到过宝石 queue<node>q; void dfs(int deep) { if(deep>ans) return; //总共最多只需封锁四个区域,即入口或出口周围的四个方向 node first,next; while(!q.empty()) q.pop(); q.push(start); memset(v,false,sizeof(v)); v[start.x][start.y][0]=true; int minstep=-1; while(!q.empty()) { first=q.front(); q.pop(); if(map[first.x][first.y]=='E'&&first.num) { minstep=first.step; break; } for(int i=0; i<4; i++) { next.x=first.x+d[i][0]; next.y=first.y+d[i][1]; if(next.x<0||next.x>=n||next.y<0||next.y>=m||map[next.x][next.y]=='#'||first.step>=T) continue; if(map[next.x][next.y]=='J') next.num=1; else next.num=first.num; if(v[next.x][next.y][next.num]) continue; v[next.x][next.y][next.num]=true; for(int j=1; j<=first.step; j++) //保存路径 { next.rox[j]=first.rox[j]; next.roy[j]=first.roy[j]; } next.step=first.step+1; next.rox[next.step]=next.x; next.roy[next.step]=next.y; q.push(next); } } if(minstep==-1) //minstep==-1表示该封锁区域设置成功,kid无法完成任务 { if(deep<ans) { ans=deep; return; } } for(int i=1; i<first.step; i++) //在kid能完成任务的路径上尝试封锁某个点 { char cc=map[first.rox[i]][first.roy[i]]; //保存要封锁的点的原先的状态 if(cc=='E'||cc=='S') continue; map[first.rox[i]][first.roy[i]]='#'; //尝试封锁该点 dfs(deep+1); //设置一个封锁区域后,继续遍历 map[first.rox[i]][first.roy[i]]=cc; //把该点设回原来的状态 } } int main() { int t; cin>>t; while(t--) { cin>>n>>m>>T; for(int i=0; i<n; i++) for(int j=0; j<m; j++) { cin>>map[i][j]; if(map[i][j]=='S') { start.x=i; start.y=j; start.step=0; start.num=0; } } ans=4; dfs(0); cout<<ans<<endl; } return 0; }