DFS算法(深度优先算法)

1.DFS算法是暴力算法,是枚举算法的另外一种形式(树上枚举)

1.1 枪挑一条线(DFS)

1.2 棍扫一大片(BFS)

2. 五种形式

2.1 排序树(孩子和祖先不重复)

2.2 组合树(孩子要比父亲大)

2.3 子集树(左孩子为0,右孩子为1,太极生两仪,两仪生四象,四象生八卦)

2.4 拆分树(孩子大于等于父亲)

2.5 搜索树(孩子和祖先不能重复)

3. 两个模板+5棵树形式

3.1 模板1 (判孩子法)

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

3.2 模板2 (判父亲法)

#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模 
int ans[N];
int vis[N];
void dfs(int k);
int main()
{
	return 0;
}
void dfs(int u) //u为父节点 
{
	//保存父亲
	//标记父亲
	if() //如果父亲是答案就输出 
	{
		
	}
	else //父亲不是答案,继续从下一代找 
	{
		for(int i=1;i<n;i++)
		{
			//生成孩子
			if() //判断孩子的合法行(符合约束条件并不重复) 
			{
				dfs(i);	
			} 
		}	
	} 
	// 取消标记(与标记父亲对应) 

}

3.3 排序树(模板1)

#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模 
int ans[N];
int vis[N];
void dfs(int k);
int n;
int main()
{
	cin>>n;
	dfs(1); //从第一代深搜 
	return 0;
}
void dfs(int k) //第k代,第k层,第k步。 
{
	for(int i=1;i<=n;i++) //枚举第K代孩子的所有线索 
	{
		//生成孩子(用i表示出孩子)
		if(vis[i]==0) //判断孩子的合法性(符合约束条件且不重复) 
		{
			//保存孩子 
			ans[k]=i;
			//标记孩子
			vis[i]=1;
			if(k>=n) //如果孩子是答案(到达叶子节点) 
			{
				for(int j=1;j<=k;j++)
				{
					cout<<ans[j]<<' ';	
				}
				cout<<endl;
			}
			else//继续从下一代找
			{
			    dfs(k+1);	
			}
			//取消标记 
			vis[i]=0;
		} 
	} 
}

3.4 组合树(模板1)

#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模 
int ans[N];
int vis[N];
void dfs(int k);
int n,r; //表示从n个数中取r个进行组合,与顺序无关 
int main()
{
	cin>>n>>r;
	dfs(1); //从第1层开始深搜 
	return 0;
}
void dfs(int k) //第k代,第k层,第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<<' ';
				}
				cout<<endl;
			}  
			else//继续从下一代找
			{
			    dfs(k+1);	
			}
			//取消标记 
		} 
	} 
}

3.5 子集树(模板1)

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

3.6 拆分树(模板1)

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

3.7 搜索树(模板2)

#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模 
int ans[N];
int vis[N];
void dfs(int u,int k);
int m,n; //n个点m条边
vector<int> a[N]; //使用动态数组存储
int start=0,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) //u为父节点 
{
	//保存父亲
	ans[k]=u;
	//标记父亲
	vis[u]=1;
	if(u==target) //如果父亲是答案就输出 
	{
		for(int j=1;j<=k;j++)
		{
			cout<<ans[j]<<" ";
		}
		cout<<endl;
	}
	else //父亲不是答案,继续从下一代找 
	{
		for(int i=0;i<a[u].size();i++)
		{
			//生成孩子
			int v=a[u][i];//v为u的第i个孩子 
			if(vis[v]==0) //判断孩子的合法行(符合约束条件并不重复) 
			{
				dfs(v,k+1);	
			} 
		}	
	} 
	// 取消标记(与标记父亲对应)
	vis[u]=0; 

}
/*
5 7
0 1
0 3
0 4
1 2
1 4
2 3
3 4
*/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值