dfs剪枝的应用以及bfs

奇怪的电梯
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i i i层楼 ( 1 ≤ i ≤ N ) (1{\leq}i{\leq}N) (1iN)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3 , 3 , 1 , 2 , 5 3,3,1,2,5 3,3,1,2,5代表了 K i ( K 1 = 3 , K 2 = 3 ⋯ ) K_i(K_1=3,K_2=3{\cdots}) Ki(K1=3,K2=3),从 1 1 1楼开始。在 1 1 1楼,按“上”可以到 4 4 4楼,按“下”是不起作用的,因为没有 − 2 -2 2楼。那么,从 A A A楼到 B B B楼至少要按几次按钮呢?

输入格式
共二行。
第一行为33个用空格隔开的正整数,表示 N , A , B ( 1 ≤ N ≤ 200 , 1 ≤ A , B ≤ N ) N , A , B ( 1 ≤ N ≤ 200 , 1 ≤ A , B ≤ N N,A,B(1≤N≤200, 1≤A,B≤N)N,A,B(1≤N≤200,1≤A,B≤N N,A,B(1N200,1A,BN)N,A,B(1N200,1A,BN)。
第二行为 N N N个用空格隔开的非负整数,表示 K i K_i Ki

输出格式
一行,即最少按键次数,若无法到达,则输出 − 1 -1 1

深度优先搜索
如果单纯的暴力搜索,会有很多重复的搜索,比如某一次搜索中已经来过了 1 1 1楼,但是进过了一番波折又来到了 1 1 1楼,那么势必会重复之前那个过程,所以之前来过的楼就不能再来一次了。

#include
#include
using namespace std;
int floor[205],N;
bool map[205];
int Min = INT_MAX;		//获取int的最大值
void dfs(int,int,int,int);
int main()
{
	int begin,end,t;
	cin>>N>>begin>>end;
	for(t=1;t<=N;t++)
	{
		cin>>floor[t];
	}
	
	if(begin == end) {
        cout << 0 << endl;
        return 0;
    }
    
    
	dfs(begin,end,begin,0);
	
	if(Min==INT_MAX)
		cout<<-1;
	else cout<<Min;
}
void dfs(int begin,int end,int now,int times)
{
	if(now==end)
	{
		if(times<Min)
		{
			Min=times;
		}
		return;
	}
	
	if(now-floor[now]>=0&&!map[now])
	{
		map[now]=true;
		dfs(begin,end,now-floor[now],times+1);
		map[now]=false;
	}
	
	if(now+floor[now]<=N&&!map[now])
	{
		map[now]=true;
		dfs(begin,end,now+floor[now],times+1);
		map[now]=false;
	}
		
}

结果超时了两个点,所以还需要进一步的剪枝,对于如何剪枝,原则是如果这个搜索是没有必要的就是把它剪掉,比如求几个数相乘等于一个数,如果发现在相乘的过程中已经大于这个数了,且乘的数都大于 1 1 1,那么就不要用搜下去了。
对于这道题因为我们是在寻找最小值,且每一次搜索值都会增加,所以在搜的过程中如果发现值已经大于最小值了,就不要再搜了。
改进后的代码

#include
#include
using namespace std;
int floor[205],N;
bool map[205];
int Min = INT_MAX;
void dfs(int,int,int,int);
int main()
{
	int begin,end,t;
	cin>>N>>begin>>end;
	for(t=1;t<=N;t++)
	{
		cin>>floor[t];
	}
	
	if(begin == end) {
        cout << 0 << endl;
        return 0;
    }
    
    map[begin]=true;
	dfs(begin,end,begin,0);
	
	if(Min==INT_MAX)
		cout<<-1;
	else cout<<Min;
}
void dfs(int begin,int end,int now,int times)
{
	if(now==end)
	{
		if(times<Min)
		{
			Min=times;
		}
		return;
	}
	
	if(times>Min)
		return;
	
	if(now-floor[now]>=0&&!map[now-floor[now]])
	{
		map[now]=true;
		dfs(begin,end,now-floor[now],times+1);
		map[now]=false;
	}
	
	if(now+floor[now]<=N&&!map[now+floor[now]])
	{
		map[now]=true;
		dfs(begin,end,now+floor[now],times+1);
		map[now]=false;
	}
		
}

完美通过!!

广度优先搜索
这道题在讨论区大家都比较推荐 b f s bfs bfs,于是我也来做一下顺便复习一下

#include
#include			//使用stl
using namespace std;
int Floor[205], N;
int map[205];
int flag, Begin;
queue<int> q;		//创建一个队列,int可以是任意的数据类型
int bfs(int, int);
int main()
{
	int end, t;
	cin >> N >> Begin >> end;
	for (t = 1; t <= N; t++)
	{
		cin >> Floor[t];
	}
	t = bfs(Begin, end);
	if (flag)
		cout << t;
	else
		cout << -1;
}

int bfs(int now_floor, int end)
{
	int temp_floor;
	q.push(now_floor);		//入队
	while (q.size())
	{
		temp_floor = q.front();		//返回队列最前面的值
		q.pop();					//弹出最后一个元素,但返回值是void
		if (temp_floor == end)
		{
			flag = 1;
			return map[temp_floor];
		}
		if (temp_floor - Floor[temp_floor] > 0 && !map[temp_floor - Floor[temp_floor]] &&
			temp_floor - Floor[temp_floor] != Begin)
		{

			q.push(temp_floor - Floor[temp_floor]);
			map[temp_floor - Floor[temp_floor]] = map[temp_floor] + 1;
		}
		if (temp_floor + Floor[temp_floor] <=N && !map[temp_floor + Floor[temp_floor]] &&
			temp_floor + Floor[temp_floor] != Begin)
		{

			q.push(temp_floor + Floor[temp_floor]);
			map[temp_floor + Floor[temp_floor]] = map[temp_floor] + 1;
		}
	}
}

可以看到使用bfs就不用考虑剪枝这种细节,但是bfs编写起来麻烦了一点

你可能感兴趣的:(dfs,dfs,剪枝)