HDOJ 1983 Kaitou Kid - The Phantom Thief (2) DFS+BFS

来源:互联网 发布:114网络预约挂号 编辑:程序博客网 时间:2024/05/17 20:30

题目是中文的,不多做解释


n*m的矩阵,最大都是8,所以可以随意暴力都不会超时!

先说说网上所有的题解的方法:贪心的思想:对起点S和终点E进行封锁,也就是说用最多四个#就可以把S框住,或者把E框住,所以答案最多为4!(之后再说明,这样想应该是有问题的,感觉HDOJ的数据不对)

那么,我们从0枚举到4,枚举量为修改多少个点

如何检测这个枚举的值是否可行呢?用bfs

在T秒的时间之内,是否可以从S走到E,而且中途遇到过J(捡到过宝石)

这又涉及到一个判重的经典的问题:加一维变量:vis【x】【y】【num】:当前坐标为(x,y),从S走到这捡到了num个宝石,这个状态是否到达过


这样分析完了就可以贴代码了:

注意细节,枚举量需要用全局变量,不仅仅是最后答案,也是dfs的判断值

还需要一个flag值,作为找到答案之后的退出值


#include<bits/stdc++.h>using namespace std;const int maxn=10;const int maxm=10;const int maxj=10;int n,m,T,ans,t;bool flag,vis[maxn][maxm][maxj];char mp[maxn][maxm];int dx[]={0,0,0,1,-1};int dy[]={0,1,-1,0,0};struct node{int x,y,j,step;}s,e;//从S到E在T步之内能够走到,并且至少有一个J bool bfs(){memset(vis,false,sizeof(vis));vis[s.x][s.y][0]=true;queue<node> q;while(!q.empty()) q.pop();node u,v;q.push(s);while(!q.empty()){u=q.front();q.pop();for(int k=1;k<=4;k++){v.x=u.x+dx[k];v.y=u.y+dy[k];v.step=u.step+1;v.j=u.j;if (mp[v.x][v.y]=='J') v.j++;if (v.x>=1&&v.x<=n&&v.y>=1&&v.y<=m&&!vis[v.x][v.y][v.j]&&mp[v.x][v.y]!='#'&&v.step<=T){vis[v.x][v.y][v.j]=true;if (v.x==e.x&&v.y==e.y&&v.j>0) return true;q.push(v);}}}return false;}void dfsstart(int num,int all){if (flag) return;if (all>ans){flag=!bfs();return;}char ch;int nx,ny;for(int k=num;k<=4;k++){nx=s.x+dx[k];ny=s.y+dy[k];if ((mp[nx][ny]=='J'||mp[nx][ny]=='.')&&nx>=1&&nx<=n&&ny>=1&&ny<=m){ch=mp[nx][ny];mp[nx][ny]='#';dfsstart(k+1,all+1);mp[nx][ny]=ch;}}return;}void dfsend(int num,int all){if (flag) return;if (all>ans){flag=!bfs();return;}char ch;int nx,ny;for(int k=num;k<=4;k++){nx=e.x+dx[k];ny=e.y+dy[k];if ((mp[nx][ny]=='J'||mp[nx][ny]=='.')&&nx>=1&&nx<=n&&ny>=1&&ny<=m){ch=mp[nx][ny];mp[nx][ny]='#';dfsstart(k+1,all+1);mp[nx][ny]=ch;}}return;}void dfs(int all){if (flag) return;if (all>ans){flag=!bfs();return;}char ch;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if (mp[i][j]=='J'||mp[i][j]=='.'){ch=mp[i][j];mp[i][j]='#';dfs(all+1);mp[i][j]=ch;}}return;}bool ok(){dfs(1);if (flag) return true;return false;}int main(){freopen("input.txt","r",stdin);scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&m,&T);for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if (mp[i][j]=='S') s.x=i,s.y=j,s.step=0,s.j=0;else if (mp[i][j]=='E') e.x=i,e.y=j,e.j=0;flag=false;for(ans=0;ans<=3;ans++)if (ok()){printf("%d\n",ans);break;}if (!flag) printf("4\n");}return 0;}


再说说这个题目的问题所在,贴个hack数据:

5 5 1000JJJJJJJSJJJJEJJJJJJJJJJJJ

这个按照标程来说,答案是4

题目中说了:不能封锁出口或者入口

所以我觉得答案应该是6,封锁成如图:

5 5 1000JJ#JJJ#S#JJ#E#JJJ#JJJJJJJ
这样就是只能从起点S到终点E,而且周围都是墙,不可能出得去


所以,我一开始的思路是,枚举起点和终点周围的4个格子,然后想着不对,起点和终点可能是相邻的,所以就干脆暴力一点,枚举全图,反正枚举量也不大,然后就一直wa!

我这组数据觉得应该是可以hack标程的

贴几组数据来hack:

95 5 1000JJJJJJJSJJJJEJJJJJJJJJJJJ5 5 1JJJJJJJSJJJJEJJJJJJJJJJJJ5 5 2JJJJJJJSJJJJEJJJJJJJJJJJJ5 5 3JJJJJJJSJJJJEJJJJJJJJJJJJ5 5 4JJJJJJJSJJJJEJJJJJJJJJJJJ5 5 1JJJJJJJSJJJJJJJJJEJJJJJJJ5 5 2JJJJJJJSJJJJJJJJJEJJJJJJJ5 5 3JJJJJJJSJJJJJJJJJEJJJJJJJ5 5 4JJJJJJJSJJJJJJJJJEJJJJJJJ


这9组的答案应该是:(按照AC代码)

4 0 0 4 4 0 0 1 3

学到了很多搜索暴力的姿势

0 0