HDU T1072 Nightmare (Bfs写法 & Dfs + 记忆化搜索 + 剪枝 写法 )

版权声明:希望能帮到弱校的ACMer成长,因为自己是弱校菜鸡~~~~ https://blog.csdn.net/Mr__Charles/article/details/82250655

                                HDU T1072 Nightmare

题解:

    第一眼看到这题,就明白了炸弹时间重置装置可以用多次,但每个点的炸弹时间重置装置只能用一次。如果你不把用过的炸弹时间重置装置标记掉,你会陷入死循环。因为本题的路可以重复走(看懂样例三就晓得了),所以,炸弹时间一直在被重置而不结束,当然就没答案了。

    鄙人一开始用的是Dfs,没写出来,后来发现没我想的那么简单,转手写Bfs,只需标记走过的炸弹时间重置装置,一发AC。

 

Bfs写法

#include<cstdio>
#include<iostream>
#include<queue>
#define maxn 8
using namespace std;

int n,m,maps[maxn][maxn];
int mov[4][2] = {-1,0,0,1,1,0,0,-1};
struct Node{
	int x,y,st,tl;
}s,e,now,nex;

bool charge(Node a){
	if(a.x < 0 || a.x >= n || a.y < 0 || a.y >= m || maps[a.x][a.y] == 0 || a.tl == 0)
	    return false;
	return true;
}

int Bfs(){
	queue<Node> Q;
	Q.push(s);
	while(!Q.empty()){
		now = Q.front();
		Q.pop();
		
		if(now.x == e.x && now.y == e.y)
		    return now.st;
		
		for(int i = 0; i < 4; ++i){
			nex.x = now.x + mov[i][0];
			nex.y = now.y + mov[i][1];
			nex.st = now.st + 1;
			nex.tl = now.tl - 1;
			if(charge(nex)){
				if(maps[nex.x][nex.y] == 4){
				    nex.tl = 6;
				    maps[nex.x][nex.y] = 0;	
				}
				Q.push(nex);
			}
		}
	}
	return -1;
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i = 0; i < n; ++i)
		    for(int j = 0; j < m; ++j){
		        scanf("%d",&maps[i][j]);
		        if(maps[i][j] == 2){
		        	s.x = i; s.y = j;
		        	s.st = 0;s.tl = 6;
		        }
		        if(maps[i][j] == 3){
		        	e.x = i; e.y = j;
		        }
		    }
		printf("%d\n",Bfs());
	}
	return 0;
}

Dfs + 记忆化搜索 + 剪枝 写法 

思路:

    上面也提到了,点可以重复走,但是每个地方的炸弹时间重置装置只用一次。

    首先

    第一处剪枝:要开step和timel 两个数组记录走过的地方的步数和所剩时间。因为你走过的点,如果再走一遍,你要判断当前的步数和所剩时间,这两者是不是比这个点原来记录的数据更优。如果不是,那何必走这个点。

    详细点说就是:

    例如A点的step数组 = 1,timel数组 = 3;从A走到B,那么B点记录的step数组 = 2,timel数组 = 2;从B回到A的话,当前状态会变为 step数组 = 3,timel = 1;跟A点原来记录的并没有更优,因为步数增加了,时间也少了,所以没必要再走回A点,这就达到了剪枝的效果。

    第二处剪枝:就是边界判断,所剩时间为0和当前步数已大于记录的步数。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define maxn 8
#define INF 0x3f3f3f3f
using namespace std;

int n,m,ans,sx,sy,ex,ey,maps[maxn][maxn];
int mov[4][2] = {-1,0,0,1,1,0,0,-1};
int step[maxn][maxn],timel[maxn][maxn];

bool charge(int x,int y){
	if(x < 0 || x >= n || y < 0 || y >= m || maps[x][y] == 0)
	    return false;
	return true;
}

void Dfs(int x,int y,int st,int tl){
	if(!charge(x,y)) return;
	if(tl == 0 || st > ans) return;
	if(x == ex && y == ey)
	    ans = min(ans,st);
	
	if(maps[x][y] == 4) tl = 6;
	
	if(st >= step[x][y] && tl <= timel[x][y]) return;
	
	step[x][y] = st;
	timel[x][y] = tl;
	
	for(int i = 0; i < 4; ++i){
		int nx = x + mov[i][0];
		int ny = y + mov[i][1];
		Dfs(nx,ny,st+1,tl-1);
	}
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i = 0; i < n; ++i)
		    for(int j = 0; j < m; ++j){
		    	step[i][j] = INF;
		    	timel[i][j] = 0;
		        scanf("%d",&maps[i][j]);
		        if(maps[i][j] == 2){
		        	sx = i; sy = j;
		        }
		        if(maps[i][j] == 3){
		        	ex = i; ey = j;
		        }
		    }
		ans = INF;
		Dfs(sx,sy,0,6);
		if(ans == INF)
		    printf("-1\n");
		else
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mr__Charles/article/details/82250655