DFS算法(深度优先搜索)

本文介绍了五种特定类型的树:排序树、组合树、子集树、拆分树和搜索树,并分别给出了使用深度优先搜索(DFS)策略进行遍历的C++代码示例。每种树的遍历方法根据其特定的约束条件进行,包括判断孩子节点或父亲节点的合法性。
摘要由CSDN通过智能技术生成

一,五种形式:

1.1排序树:孩子不与祖先重复

1.2组合树:孩子要大于父亲

1.3子集树:左孩子为0,右孩子为1

1.4拆分树:孩子要大于等于父亲

1.5搜索树:孩子不与祖前重复

二,判答案的两种方法

2.1判孩子(当根结点为虚空的时候适合,比如子集树,排列树,组合树,拆分树)

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
void dfs(int k);//第k层,第k代
int ans[N];//记录答案
int vis[N];//标记变量,去重 
int main()
{

	return 0;
}
void dfs(int k)
{
	for(int i=1;i<=N;i++)//枚举第k代的所有孩子的线索 
	{
		//生成孩子(用i表示出孩子) 
		if()//判孩子的合法性(符合约束条件并且不重复) 
		{
			//保存孩子
			//标记孩子
			if()//如果孩子是答案就输出 
			{
				
			} 
			else//如果孩子不是答案,继续从下一代找 
			{
				dfs(k+1);
			}
			//取消标记 
		}
	}
}

2.2判父亲(当根节点不是虚空的时候适合,比如搜索树)

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题的规模
void dfs(int u);//u为父亲结点
int ans[N];//记录答案
int vis[N];//标记变量,去重 
int main()
{

	return 0;
}
void dfs(int u)
{
	//保存父亲
	//标记父亲
	if()//如果父亲是答案就输出(判父亲法) 
	{
		//输出答案 
	} 
	else//如果父亲不是答案,继续从下一代找 
	{
		for(int i=1;i<=N;i++)//枚举第u代的所有孩子的i 
		{
			//生成孩子
			if()//判断孩子的合法性 
			{
				dfs(i);//递归搜索u的孩子 
			} 
		}
	}
	//取消标记 
}

三,代码

3.1排序树

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
void dfs(int k);//第k层,第k代
int ans[N];//记录答案
int vis[N];//标记变量,去重 
int main()
{
	dfs(1);//从第一步开始 
	return 0;
}
void dfs(int k)
{
	for(int i=1;i<=3;i++)//枚举第k代的所有孩子的线索 
	{
		//生成孩子(用i表示出孩子) 
		if(vis[i]==0)//判孩子的合法性(符合约束条件并且不重复) 
		{
			//保存孩子
			ans[k]=i;
			//标记孩子
			vis[i]=1;
			if(k>=3)//如果孩子是答案就输出 
			{
				for(int j=1;j<=3;j++)
				{
					cout<<ans[j];
				}
				cout<<endl;
			} 
			else//如果孩子不是答案,继续从下一代找 
			{
				dfs(k+1);
			}
			//取消标记 
			vis[i]=0;
		}
	}
}

3.2组合树

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
void dfs(int k);//第k层,第k代
int ans[N];//记录答案
int n, r;//表示从n个树中选r个 
int main()
{
	cin>>n>>r;
	dfs(1); 
	return 0;
}
void dfs(int k)
{
	for(int i=1;i<=n;i++)//枚举第k代的所有孩子的线索 
	{
		//生成孩子(用i表示出孩子) 
		if(i>ans[k-1])//判孩子的合法性(符合约束条件并且不重复),自动去重,不需要标记再去重 
		{
			//保存孩子
			ans[k]=i;
			//标记孩子
			if(k>=r)//如果孩子是答案就输出 
			{
				for(int j=1;j<=k;j++)
				{
					cout<<ans[j]<<" ";
				}
				cout<<endl;
			} 
			else//如果孩子不是答案,继续从下一代找 
			{
				dfs(k+1);
			}
			//取消标记 
		}
	}
}

3.3子集树

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
void dfs(int k);//第k层,第k代
int ans[N];//记录答案,ans[i]=0表示不选,ans[i]=1表示选 
int n;//表示有n个物品 
int main()
{
	cin>>n;
	dfs(1); 
	return 0;
}
void dfs(int k)
{
	for(int i=0;i<=1;i++)//枚举第k代的所有孩子的线索 
	{
		//生成孩子(用i表示出孩子) 
		if(1)//判孩子的合法性(符合约束条件并且不重复) 
		{
			//保存孩子
			ans[k]=i;
			//标记孩子
			if(k>=n)//如果孩子是答案就输出 
			{
				for(int j=1;j<=k;j++)
				{
					cout<<ans[j]<<" ";
				}
				cout<<endl;
			} 
			else//如果孩子不是答案,继续从下一代找 
			{
				dfs(k+1);
			}
			//取消标记 
		}
	}
}

3.4拆分树

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
void dfs(int s,int k);//第k层,第k代
int ans[N];//记录答案
int vis[N];//标记变量,去重 
int n;
int main()
{
	cin>>n;
	ans[0]=1;//初始化一定要加 
	dfs(n,1);//将n进行拆分 
	return 0;
}
void dfs(int s,int k)
{
	for(int i=1;i<=s;i++)//枚举第k代的所有孩子的线索 
	{
		//生成孩子(用i表示出孩子) 
		if(i>=ans[k-1])//判孩子的合法性(符合约束条件并且不重复) 
		{
			//保存孩子
			ans[k]=i;
			//标记孩子
			s-=i;
			if(s==0)//如果孩子是答案就输出 
			{
				for(int j=1;j<=k;j++)
				{
					cout<<ans[j]<<" ";
				}
				cout<<endl;
			} 
			else//如果孩子不是答案,继续从下一代找 
			{
				dfs(s,k+1);
			}
			//取消标记 
			s+=i;
		}
	}
}

3.5搜索树(找出从起点到终点的所有路径)

#include<bits/stdc++.h>
using namespace std;
#define N 1000//问题规模的大小
//存储图 
int n, m;//n个点,m条边 
vector<int> a[N];

void dfs(int u,int k);//第k层,第k代
int ans[N];//记录答案
int vis[N];//标记变量,去重 
//找从起点到终点的所有路径
int start=0;//起点 
int target=2;//终点 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int u, v;
		cin>>u>>v;
		a[u].push_back(v);
		a[v].push_back(u);
	} 
	dfs(start,1);
	return 0;
}
void dfs(int u,int k)
{
	//保存父亲
	ans[k]=u;
	//标记父亲
	vis[u]=1;
	if(u==target)//如果父亲是答案就输出(判父亲法) 
	{
		//输出答案
		for(int i=1;i<=k;i++)
		{
			cout<<ans[i]<<" ";
		}
		cout<<endl; 
	} 
	else//如果父亲不是答案,继续从下一代找 
	{
		for(int i=0;i<a[u].size();i++)//枚举第u代的所有孩子的i 
		{
			//生成孩子
			int v=a[u][i];//u的第i个孩子 
			if(vis[v]==0)//判断孩子的合法性 
			{
				dfs(v,k+1);//递归搜索u的孩子 
			} 
		}
	}
	//取消标记 
	vis[u]=0;
}
/*
5 7
0 1
0 3
0 4
1 2
1 4
2 3
3 4
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值