图遍历算法的应用

在问题求解时,对所有可能的问题解构成一棵树,而最优树或者符合要求的解就是该树的一条路径或者一个结点。这种树称为解答树

1、全排列问题。求1,2…n的全排列有n!个。可以通过图的深度优先遍历输出全排列。

递归调用深度优先遍历。递归函数的参数为遍历的结点数。递归结束的条件为:所有的数都已经在输出的路径上。返回上一层,重新查找另一条输出路径。

#include<iostream>
#include<string.h>
using namespace std;

const int N=10;//n的最大值
int S[N];//记录解
int V[N];//记录当前值是否已经被遍历,0表示没有,1表示有
int n;//输入的n值

void DFS(int depth)
{
	if(depth>=n)//深度遍历到了叶子结点,输出当前一条路径,depth代表了遍历的结点数
	{
		for(int i=0;i<n;i++)
			cout<<S[i]<<" ";
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++)//遍历数1,2…n
	{
		if(!V[i])//当前结点没有遍历
		{
			V[i]=1;//已遍历
			S[depth]=i;//记录当前结点到路径上
			DFS(depth+1);//遍历的路径上结点数增1
			V[i]=0;//返回上一层结点重新查找下一个结点
		}
	}
}

void main()
{	
	cin>>n;
	memset(V,0,n);//将数组V大小为n的内容全部置为0
	DFS(0);
}

2、硬币组合问题。有1分、2分、5分、10分四种硬币,每种硬币数量无限,给定Target分钱,求有多少种组合可以合成Target分钱?

同样可以采用递归调用深度优先遍历搜索的方法。递归函数的参数为当前要加入的硬币的索引。递归终止的条件:已经达到了给定的Target分钱或者超过了给定的Target分钱。

#include<iostream>
#include<vector>
using namespace std;

int Target;//给定的金额
const int N=4;//硬币的种类数
int coin[]={1,2,5,10};//四种硬币
int total;//组合的金额
vector<int> solution;//解集,一种解中的硬币组合
int count;//记录有多少种组合

void DFS(int index)
{
	if(total==Target)//是一种解
	{
		count++;//组合数增1
		cout<<count<<": ";
		for(int i=0;i<solution.size();i++)
			cout<<solution[i]<<" ";//输出当前的硬币组合
		cout<<endl;
		return;
	}
	if(total>Target)//组合的金额大于给定的金额
		return;
	for(int i=index;i<N;i++)
	{
		total+=coin[i];
		solution.push_back(coin[i]);//当前硬币加入当前组合中
		DFS(i);
		solution.pop_back();//递归结束,返回上一层,加入下一种硬币
		total-=coin[i];
	}
}

void main()
{	
	cin>>Target;
	DFS(0);
}

3、求1到n个自然数组成的集合的所有组合问题。在构造的树中,每遍历到一个结点都有两条路径,路径边上分别为1或者0。我们所要得到的集合是每遍历到一个结点输出路径上边为1代表的结点即可。

#include<iostream>
using namespace std;

const int N=100;//允许的n最大取值
int solution[N];//解向量,为1表示当前值在集合中,为0表示不在
int n;//n的值

void DFS(int depth)
{
	if(depth>=n)
	{
		for(int i=0;i<n;i++)
			if(solution[i])//不为0在当前集合中则输出
				cout<<i+1<<" ";
		cout<<endl;
		return;
	}
	solution[depth]=0;//当前结点不加入集合中
	DFS(depth+1);
	solution[depth]=1;//当前结点加入集合中
	DFS(depth+1);
}

void main()
{	
	cin>>n;
	DFS(0);
}

4、0/1背包问题。有N件物品和一个容量为W的背包,第i件物品的重量是w[i],价值是v[i],求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。可以用深度优先遍历解决。构造解答树,边上权值为1表示加入当前物品到背包中,否则不加。

#include<iostream>
using namespace std;

const int N=100;//物品的最大件数
int solution[N];//保存解,为1表示当前物品在背包中,为0不在
int ans;//保存解,记录当前背包的总价值
int n=3;//物品件数
int W=10;//背包载重量
int weight[N]={3,4,5};//每件物品的重量
int value[N]={4,5,6};//每件物品的价值

//参数depth表示树的深度即遍历的物品数目
//cur_weight表示当前背包的重量,cur_value表示当前背包物品的价值
void DFS(int depth,int cur_weight,int cur_value)
{
	if(cur_weight>W)//背包重量超重,返回回到树的上一层
		return;
	if(cur_value>ans)//如果当前解更优则更新
		ans=cur_value;
	if(depth>n)//超过了树的深度即所有物品都遍历了,返回回到树的上一层
		return;
	//深度优先搜索,将当前物品加入或者不加入背包中
	DFS(depth+1,cur_weight,cur_value);//不加入
	DFS(depth+1,cur_weight+weight[depth],cur_value+value[depth]);//加入
}

void main()
{	
	//测试
	DFS(0,0,0);
	cout<<ans<<":"<<endl;
	cout<<endl;
}

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/zj20320/article/details/52128517
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞