DFS+剪枝 BFS 鸣人和佐助

题目:鸣人和佐助

佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?
DFS+剪枝 BFS 鸣人和佐助_第1张图片
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?

输入

输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。

输出

输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。

样例输入
样例输入1

4 4 1
#@##
**##
###+
****

样例输入2

4 4 2
#@##
**##
###+
****

样例输出
样例输出1
6

样例输出2
4

解题思路:

dfs+剪枝
dfs:
首先dfs鸣人的点,再接着dfs鸣人四周的各点;
终止条件——查克拉<0
最优性剪枝:
*剪枝1:*创建三维数组sep,初始值设置为最大值,将当前x,y,查克拉所费的时间数(temptime)保存至sep[x][y][查克拉],若再次来到该点x,y且拥有相同的查克拉,而时间数更大的话,那此次dfs的总时间数必将大于前者,即不可能为最少时间——遗弃之。
*剪枝2:*当前所用时间大于最快的总时间——遗弃之。

#include
#include
using namespace std;

int Time;        //找到佐助的最少时间
int temptime;    //过程中的时间数,每次dfs前归零
int M,N,T;       //M为行数,N为列数,T为查克拉数
char map[210][210];  //保存地图
int narotoX;  //鸣人的初始行 
int narotoY;  //鸣人的初始列 
int visited[210][210];    //初始为0,当此遍历时走过则标记为1,防止重复走同一个点.
int lx[4]={1,-1,0,0};      //下一个行数的遍历数组
int ly[4]={0,0,1,-1};      //下一个列数的遍历数组
int x1,y1;               
int sep[210][210][12];      //三维数组————为最优性剪枝用

void Dfs(int x, int y,int chakora){
	if(x<0||x>=M||y<0||y>=N||visited[x][y]) return;   //走到地图外了——直接失败返回
	if (chakora<0) return;             //查克拉小于0,直接失败返回
	if(temptime>=Time) return;            //剪枝2,失败返回
	if(temptime>=sep[x][y][chakora]) return;  //剪枝1,失败返回
	      
	sep[x][y][chakora]=temptime;       //这时temptime必小于sep[x][y][chakora],保存之        
	if(map[x][y]=='#') chakora--;	   //当前xy有敌人,查克拉减少		
	else if (map[x][y]=='+'){         //当前xy有佐助
		if(temptime<Time) Time=temptime;      //判断此时temptime是小于最少时间,是则保存之
		return;
	}
	
	visited[x][y]=1;             //标记为已访问
	temptime++;                  //时间+上
	for(int i=0;i<4;i++){         //dfs上下左右四个点
		 x1=x+lx[i];                             
		 y1=y+ly[i];
		 Dfs(x1,y1,chakora);
	}
	visited[x][y]=0;         //都遍历完成——返回上层并将此点标记为未访问
	temptime--;              //访问这个点用的时间也剪掉
}

int main(){
	while(cin>>M>>N>>T){
	for (int i=0;i<M;i++)
		for (int j=0;j<N;j++){
			cin>>map[i][j];
			if (map[i][j]=='@'){
				narotoX=i;
				narotoY=j;}}         //保存鸣人的位置
				
		memset(sep,0x3f,sizeof sep);     //初始化sep为极大值
		//关于为什么要赋值为0x3f↓
		//http://www.manongjc.com/detail/10-jreyaemnqbgivzi.html 
		 Time=1<<30;
		 temptime=0;      //初始化temptime
		 Dfs(narotoX,narotoY,T);
		 if (Time==1<<30) cout<<"-1"<<endl;
		 else cout<<Time<<endl;
	}
		 return 0;
}

BFS算法
找到的第一个解一定是最短解,无需像dfs一样考虑剪枝

#include
#include
#include
using namespace std;
//关键思路:状态比位置多一维,即处于该位置时的查克拉数目 
//无需剪枝——找最优解比dfs方便
int M,N,T;
char map[220][220];
int Nx,Ny;
int dp[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int x1,y1;
int flag;
struct NRT{
	int x;
	int y;
	int steps;   //所需步数 
	int C;//查克拉 
	NRT(int xx,int yy,int s,int cc):x(xx),y(yy),C(cc),steps(s){
	}     //初始化结构函数,方便转移
};
  //创建队列,存放头节点 
int visited[220][220][15];  
//访问过的xy   是三位数组——还包括查克拉数  !!!有三个状态)——三维数组!很关键 

int main(){
	while(cin>>M>>N>>T){
	queue <NRT>F;	 //每次输入都要清空队列——很关键 
	for (int i =0;i<M;i++)
		for (int j=0;j<N;j++){
			cin>>map[i][j];
			if (map[i][j]=='@'){
				Nx=i;   //鸣人所在的行 
				Ny=j;  //鸣人所在的列 
			}
		}
		//找最少时间,用BFS更好
	//设定起始位置
	memset(visited,0,sizeof visited);
	 F.push(NRT(Nx,Ny,0,T));  //鸣人入队
	 visited[Nx][Ny][T]=1;
	 while(!F.empty()){      
	 	flag=0;
	 	NRT s=F.front();
		 	for (int t=0;t<4;t++){       
		 		x1=s.x+dp[t][0];
		 		y1=s.y+dp[t][1];
				if(x1<0||x1>=M||y1<0||y1>=N) continue;//超出地图边界
		 		if(visited[x1][y1][s.C]) continue;        //已入过队列 
		 		
		 		if(map[x1][y1]=='+'){    //找到
				 	cout<<s.steps+1<<endl;       //输出步数+1
				 	flag=1;        //退出标记
				 	break;     //退出
				 }
		 		if(map[x1][y1]=='#'&&s.C>0){
		 			F.push(NRT(x1,y1,s.steps+1,s.C-1));       //查克拉-1
		 			visited[x1][y1][s.C-1]=1;
				 }
				 if(map[x1][y1]=='*'){           //查克拉不减
				 	F.push(NRT(x1,y1,s.steps+1,s.C));
				 	visited[x1][y1][s.C]=1;
				 }
			 }
			 F.pop();
			 if(flag==1){
			 	break;
			 }
	 }
	 if (flag==0) {        //没找到
	 	cout<<"-1"<<endl;
	 }
	 }
	 return 0;
}

你可能感兴趣的:(算法,DFS,BFS)