版权声明:希望能帮到弱校的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;
}