HDU 1010 Tempter of the Bone (剪枝)

                                     Tempter of the Bone


'X': a block of wall, which the doggie cannot enter; 
'S': the start point of the doggie; 
'D': the Door; or
'.': an empty block.

输入n,m,t

n * m的地图

题意:从s出发,初始时间为0, 只有在第t秒,D会开门,判断能否走出迷宫。

思路:暴搜,没有剪枝预判的话会超时。

剪枝:

假设sx,sy为起点,则ex,ey为终点,任意点

如果

1.abs(sx - ex) + abs(sy - ey) > t

2.abs(sx - ex) + abs(sy - ey) % 2 != t % 2(即到达D的时候时间不同步)

以上任意情况则一定不能走出去了

每次在迷宫移动的时候,同理,对此剪枝。

#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<list>
#define mod 998244353
#define INF 0x3f3f3f3f
#define Min 0xc0c0c0c0
#define mst(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(int i = a; i < b; i++)
using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 5;
int n, m, t;
int sx, sy, ex, ey;
char maps[10][10];
bool vis[10][10];
bool flag;
const int fx[4] = {1, 0, -1, 0};
const int fy[4] = {0, 1, 0, -1};
void dfs(int x, int y, int sum){
    if(maps[x][y] == 'D' && sum == t){
        flag = true;
        return ;
    }
    if(flag){
        return ;
    }
    for(int i = 0; i < 4; i++){
        int nx = x + fx[i], ny = y + fy[i];
        int tmp = abs(nx - ex) + abs(ny - ey);        //剪枝
        if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && maps[nx][ny] != 'X' && (sum + tmp + 1 <= t) && (sum + tmp + 1) % 2 == (t % 2) && !vis[nx][ny]){
            vis[nx][ny] = 1;
            dfs(nx, ny, sum + 1);
            vis[nx][ny] = 0;
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    //freopen("c1.txt", "w", stdin);
    //freopen("c2.txt", "r", stdout);
    int cas = 1;
    while(cin>>n>>m>>t){
       if(n == 0 && m == 0 && t == 0){
            break;
       }
       for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m ;j++){
                cin>>maps[i][j];
                if(maps[i][j] == 'S'){
                    sx = i, sy = j;
                }
                if(maps[i][j] == 'D'){
                    ex = i, ey = j;
                }
            }
       }
       mst(vis);
       flag = false;
       int tmp = abs(ex - sx) + abs(ey - sy);    
       if(tmp > t || tmp % 2 != t % 2){    //预判
            cout<<"NO"<<endl;
            continue;
       }
       vis[sx][sy] = 1;
       dfs(sx, sy, 0);
       if(flag){
            cout<<"YES"<<endl;
       }
       else {
            cout<<"NO"<<endl;
       }
    }
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

 

 另一种方法:

修改'X'的标记,奇偶剪枝不变

#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int dir[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
char maps[10][10];
int sx, sy, ex, ey;
int n, m, t;
bool flag;

bool inbound(int x, int y) {	//边界判断 & 墙壁判断
	return (x >= 0 && x < n && y >= 0 && y < m && maps[x][y] != 'X');
}
void dfs(int x, int y, int times) {
	if (times > t || flag) return;
	if (times == t && x == ex && y == ey) {
		flag = true;
		return;
	}
	int remain = t - times - (abs(x - ex) + abs(y - ey));
	if (remain < 0 || remain & 1) return;	//奇偶剪枝
	for (int i = 0; i < 4; i++) {
		int fx = x + dir[i][1];
		int fy = y + dir[i][0];
		if (inbound(fx, fy)) {
			maps[fx][fy] = 'X';		
			dfs(fx, fy, times + 1);
			maps[fx][fy] = '.';		//回溯
		}
	}
}
int main() {

	while (scanf("%d%d%d", &n, &m, &t) != EOF) {
		if (n == 0 && m == 0 && t == 0) break;
		flag = false;
		for (int i = 0; i < n; i++) {
			scanf("%s", maps[i]);
		}
		int block = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (maps[i][j] == 'S') {
					sx = i, sy = j;
				}
				else if (maps[i][j] == 'D') {
					ex = i, ey = j;
				}
				else if (maps[i][i] == 'X') {
					block++;
				}
			}
		}
		if (n * m - block <= t) {	//剪枝
			printf("NO\n");
			continue;
		}
		maps[sx][sy] = 'X';
		dfs(sx, sy, 0);
		if (flag) {
			printf("YES\n");
		}
		else {
			printf("NO\n");
		}
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值