HDOJ 1983 Kaitou Kid - The Phantom Thief (2) DFS+BFS
题目是中文的,不多做解释
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 1000
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
这个按照标程来说,答案是4
题目中说了:不能封锁出口或者入口
所以我觉得答案应该是6,封锁成如图:
5 5 1000
JJ#JJ
J#S#J
J#E#J
JJ#JJ
JJJJJ
这样就是只能从起点S到终点E,而且周围都是墙,不可能出得去 所以,我一开始的思路是,枚举起点和终点周围的4个格子,然后想着不对,起点和终点可能是相邻的,所以就干脆暴力一点,枚举全图,反正枚举量也不大,然后就一直wa!
我这组数据觉得应该是可以hack标程的
贴几组数据来hack:
9
5 5 1000
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
5 5 1
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
5 5 2
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
5 5 3
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
5 5 4
JJJJJ
JJSJJ
JJEJJ
JJJJJ
JJJJJ
5 5 1
JJJJJ
JJSJJ
JJJJJ
JJEJJ
JJJJJ
5 5 2
JJJJJ
JJSJJ
JJJJJ
JJEJJ
JJJJJ
5 5 3
JJJJJ
JJSJJ
JJJJJ
JJEJJ
JJJJJ
5 5 4
JJJJJ
JJSJJ
JJJJJ
JJEJJ
JJJJJ
这9组的答案应该是:(按照AC代码)
4 0 0 4 4 0 0 1 3
学到了很多搜索暴力的姿势