DFS 深度优先搜索

DFS 深度优先搜索

第一题 全排列问题
题目: 输出自然数 1 到n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
思路 : 这里用递归每次寻找第d个位置的数,放进去然后标记递归回溯,这样到n个的时就输出。
代码:

#include<bits/stdc++.h> 
using namespace std;
int n,i;
bool vis[11];
int ans[11];
void dfs(int d)
{
	if(d==n+1)
	{
		for(int i=1;i<=n;i++)
		{
			cout<<"    "<<ans[i];
		}
		cout<<endl;
		return ;
	}
	else
	{
		for(int j=1;j<=n;j++)
		{
			if(vis[j]==1) continue;
			ans[d]=j;
			vis[j]=1;
			dfs(d+1);
			vis[j]=0;
		}
	}
}
int main()
{ 
	cin>>n;
	dfs(1); 
	return 0; 
}

第二题 组合的输出
题目: 排列与组合是常用的数学方法,其中组合就是从n个元素中抽出 r个元素(不分顺序且 ),我们可以简单地将n 个元素理解为自然数 ,从中任取 个数。现要求你用递归的方法输出所有组合。
思路: 还是用递归,跟前面不同的是取r个位置,每次递归这个位置的前一个位置的下一个数,这样就不用考虑重复了。
代码:

#include<bits/stdc++.h> 
using namespace std;
int n,i,r;
bool vis[23];
int ans[23];
void dfs(int d)
{
	if(d==r+1)
	{
		for(int i=1;i<=r;i++)
		{
			cout<<"    "<<ans[i];
		}
		cout<<endl;
		return ;
	}
	else
	{
		for(int j=ans[d-1]+1;j<=n;j++)
		{
			ans[d]=j;
			dfs(d+1);
		}
	}
}
int main()
{ 
	cin>>n>>r;
	dfs(1); 
	return 0; 
}

第二题 自然数和分解
题目: 把自然数N分解为若干个大于 0 自然数之和,输出方案数。
思路: 把这个数看成和,然后每次枚举一个数来减和,到和减完,累加器加一。
代码:

#include<bits/stdc++.h> 
using namespace std;
int n,sum;
bool vis[110];
int ans[110];
void dfs(int n,int x)
{
	if(n==0)
	{
		sum++;
		return ;
	}
	else
	{
		for(int j=x;j<=n;j++)
		{
			dfs(n-j,j);
		}
	}
}
int main()
{ 
	cin>>n;
	dfs(n,1);
	cout<<sum<<endl;
	return 0; 
}

第三题 有重复元素的排列问题
题目: 设R=r1,r2,r3…rn是要进行排列的n个元素。其中元素可能相同。试设计一个算法,列出的R所有不同排列。给定以及待排列的个元素。计算出这个元素的所有不同排列。
思路: 可以先统计每个字母的个数,然后递归每次每个字母,如果这次出完了就不能出这类字母了,这样就不会重复了。
代码:

#include<bits/stdc++.h> 
using namespace std;
int n,sum;
char ans[550];
int s[30];
char a[550];
void dfs(int d)
{
	if(d==n+1)
	{
		for(int i=1;i<=n;i++)
		{
			cout<<ans[i];
		}
		sum++;
		cout<<endl;
		return ;
	}
	else
	{
		for(int i=1;i<=26;i++)
		{
			if(s[i]!=0)
			{
				ans[d]='a'+i-1;
				s[i]--;
				dfs(d+1);
				s[i]++;
			}
		}
	}
}
int main()
{ 
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[a[i]-'a'+1]++;
	}
	dfs(1);
	cout<<sum<<endl;
	return 0; 
}

第四题 最佳调度问题
题目: 假设有个n任务由k个可并行工作的机器完成。完成任务需要的时间为ti。试设计一个算法找出完成这个任务的最佳调度,使得完成全部任务的时间最早。
思路: 先从大到小排个序,然后递归每个机器的工作时间,在每次取机器的最大值,如果k个机器都好了,就比较那个最小,如果在途中就比他大了,就直接退出。
代码

#include<bits/stdc++.h> 
using namespace std;
int n,i,k,sum,a[60],minn=INT_MAX/3,x[60];
bool cmp(int a,int b)
{
	return a>b;
}
void dfs(int d,int maxn)
{
	if(maxn>=minn) return ;
	if(d==n+1)
	{
		minn=maxn;
		return ;
	}
	else
	{
		for(int i=1;i<=k;i++)
		{
			x[i]+=a[d];
			dfs(d+1,max(x[i],maxn));
			x[i]=x[i]-a[d];
		}
	}
}
int main()
{ 
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1,cmp);
	dfs(1,0);
	cout<<minn<<endl;
	return 0;
}

第五题 N皇后问题
题目: 在一张N*N的国际象棋棋盘上,放置N个皇后,使得所有皇后都无法互相直接攻击得到,(皇后可以直接攻击到她所在的横行,数列,斜方向上的棋子),现在输入一个整数N,表示在的棋盘上放个N皇后,请输出共有多少种使得所有皇后都无法互相直接攻击得到的方案数。
思路: 跟全排列差不多就是加一个左斜线和右斜线和列的判断。画个图就发现,左斜线是行和列相加,右斜线是行和列相减。
代码

#include<bits/stdc++.h>
using namespace std;
int n,ans;
bool y[100],lx[100],rx[100];
void dfs(int d)
{
	if(d==n+1)
	{
		ans++;
		return ;
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if( y[i]==1 || rx[i-d+n]==1 || lx[i+d]==1) continue;
			y[i]=1; rx[i-d+n]=1; lx[i+d]=1;
			dfs(d+1);
			y[i]=0; rx[i-d+n]=0; lx[i+d]=0;
		}
	}
}
int main()
{
	cin>>n;
	dfs(1);
	cout<<ans<<endl;
	return 0;
} 

第六题 迷宫
题目: 在N*N的迷宫内,“#”为墙,“.”为路,“s”为起点,“e”为终点,一共4个方向可以走。从左上角((0,0)“s”)位置处走到右下角((n-1,n-1)“e”)位置处,可以走通则输出YES,不可以走则输出NO。
思路: 每次递归上下左右四个位置,还要记录之前来的位置,好要判断是否是墙或者超界了,直到搜到终点。
代码

#include<bits/stdc++.h>
using namespace std;
int n,ans,k;
char a[20][20];
bool f,vis[20][20];
bool can(int x,int y)
{
	if(a[x][y]=='#') return 0;
	if( !(x>0&&x<=n) || !(y>0&&y<=n) ) return 0;
	return 1;
}
void dfs(int x,int y)
{
	if (f == 1) return;
	if(a[x][y]=='e')
	{
		cout<<"YES"<<endl;
		f=1;
		return ;
	}
	else
		{
			if(can(x+1,y) && vis[x+1][y]==0) //右
			{
				vis[x+1][y]=1;
				dfs(x+1,y);
			}
			if(can(x,y+1) && vis[x][y+1]==0) //下
			{
				vis[x][y+1]=1;
				dfs(x,y+1);
			}
			if(can(x,y-1) && vis[x][y-1]==0) //上
			{
				vis[x][y-1]=1;
				dfs(x,y-1);
			}
			if(can(x-1,y) && vis[x-1][y]==0) //左
			{
				vis[x-1][y]=1;
				dfs(x-1,y);
			}
		}
}
int main()
{
	cin>>k;
	while(k--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				cin>>a[i][j];
			}
		dfs(1,1);
		if(f==0) cout<<"NO"<<endl;
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度优先搜索DFS)是一种图遍历算法,适用于解决图的连通性、遍历和寻找路径等问题。在应用DFS算法时,常常需要将图的结构表示为数组。 建立一个DFS深度优先搜索数组时,可以按照以下步骤进行操作: 1. 首先,创建一个与图中顶点数量相等的数组,用于记录每个顶点的访问状态。初始时,将所有的数组元素初始化为未访问状态。 2. 然后,选择一个起始顶点,将其标记为已访问,并将该顶点入栈。 3. 从起始顶点开始,循环执行以下步骤:弹出栈顶元素(当前顶点),并输出该顶点的值; 4. 遍历该顶点的所有邻接顶点,若某个邻接顶点未被访问,则将其标记为已访问,并将其入栈。 5. 若当前顶点没有未被访问的邻接顶点,则继续弹出栈顶元素,即回溯到上一个顶点,直到栈为空。 6. 当图中所有顶点都被访问过后,DFS深度优先搜索结束。 通过上述步骤,我们可以将图的结构以数组的形式表示,并使用DFS算法进行遍历。在数组中,每个元素代表一个顶点,其对应的值表示该顶点是否已经被访问。通过设置一个栈来保存待访问的顶点,不断地出栈和入栈的操作,实现了DFS算法的深度遍历特性。 需要注意的是,数组的索引可以用来唯一标识顶点,索引值对应的元素则表示该顶点的访问状态。此外,可以根据具体需求,对数组进行扩展,以记录其他需要的信息,比如顶点的父节点、访问时间等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值