第七次训练 G题

问题链接:Problem G

问题简述:

给出一幅地图,已知狗的起点S,终点门D的坐标,门只在时间t开启,而狗每次移动后,以前踏过的地板便会下沉消失(即不能走重复的路),问狗能否在指定的时间T到达门。

问题分析:

此题并非求最短路径,因此用BFS并不合适,因BFS同时向多条路径并发,容易影响到其他路径的方向导致答案错误,若不标记路径,又容易队列过长而TLE,因此DFS会更适合该题。但光用DFS,由于其每次搜索都会遍历全图的特性,会导致TLE,因此需要剪枝。

  1. 第一次剪枝:当步骤数已经大于时间T时,不需要再进行搜索
  2. 第二次剪枝:当已经找到答案时,不需要再进行搜索
  3. 第三次剪枝比较复杂,我们先将map以0,1编号;
    0 1 0 1 0 1
    1 0 1 0 1 0
    0 1 0 1 0 1
    1 0 1 0 1 0
    0 1 0 1 0 1
    可见0走奇数步只能到1,走偶数步只能到0.可见四个方向行走的地图具有“奇偶性”,其奇偶性为点坐标相加对 2取余。
    因此第三次剪枝可为:当S与D的奇偶性相同时,若t为奇数,则不能走,当S与D的奇偶性不同时,若t为偶数,则也不能走。
    至此问题已经解决。

AC通过的C++语言程序如下:

#include<iostream>
#include<cstdio>
#include<cstdlib> 
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
char map[10][10];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
bool vis[10][10];
int n,m,t;
bool flag;
bool edge(int x,int y){
	if(x>=0&&y>=0&&x<n&&y<m&&map[x][y]!='X'&&vis[x][y]==0){
		return 1;
	}
	else{
		return 0;
	}
}
void DFS(int x,int y,int step){
	if(map[x][y]=='D'&&step==t){
		flag=1;
		return;
	}
	if(step>t){
		return;
	}
	for(int i=0;i<4;i++){
		int next_x=x+dir[i][0];
		int next_y=y+dir[i][1];
		if(edge(next_x,next_y)){
			vis[next_x][next_y]=1;
			DFS(next_x,next_y,step+1);
			vis[next_x][next_y]=0;
			if(flag){
				return;
			}
		}
	}
}
int main(){
	std::ios::sync_with_stdio(false);
	while(cin>>n>>m>>t){
		if(!n&&!m&&!t){
			break;
		}
		flag=0;
		memset(vis,0,sizeof(vis));
		int sx,sy,dx,dy;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				cin>>map[i][j]; 
				if(map[i][j]=='S'){
					sx=i;
					sy=j;
				}
				if(map[i][j]=='D'){
					dx=i;
					dy=j;
				}
			} 
		}
		int ps=(sx+sy)%2;
		int pd=(dx+dy)%2;
		int pt=t%2;
		if(ps!=pd&&!pt){
			cout<<"NO"<<endl;
			continue;
		}
		else if(ps==pd&&pt){
			cout<<"NO"<<endl;
			continue;
		}
		vis[sx][sy]=1;
		DFS(sx,sy,0);
		if(flag){
			cout<<"YES"<<endl;
		}
		else{
			cout<<"NO"<<endl;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值