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

学到了很多搜索暴力的姿势
全部评论

相关推荐

10-30 10:16
南京大学 Java
永远的鹅孝子:给南大✌️跪了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务