深度优先搜索 DFS,以例题来熟悉dfs

深度优先搜索 DFS

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.

深度优先搜索特别适用于那些探索所有的可能性的这些问题(穷举)。

以例题来熟悉dfs

例题
1.1~n的全排列

#include <stdio.h>
#include <iostream>
using namespace std;
int a[101],v[101],n;//v[]用于标记是否搜索过 
void print()	//打印排列 
{
	int i;
	for(i=1;i<=n;i++)//去掉了a[0],所以下方a从1开始 
	{
		cout<<a[i]<<' ';
	}
	cout<<endl;
}
void dfs(int i) //i为a[]的第i位 
{
	int j;
	if(i==n+1)	//如果i==n+1,表示前n个数已经排好 
	{
		print();
		return;
	}
	for(j=1;j<=n;j++)//每次搜索从1开始尝试 
	{
		if(v[j]==0)//数字是否使用过 
		{
			a[i]=j;//当前位置存放未使用的数字 
			v[j]=1;//该位置标记为使用过 
			dfs(i+1);//进行下一个位置的数字放置 
			v[j]=0;//回溯,当满足一种全排列后,进行下一种尝试
		}
	}
}
int main()
{
	cout<<"1--n的全排列,请输入n:";
	cin>>n;
	dfs(1);//dfs(0)是从a[0]开始
	return 0;
}

该题模板

int dfs(int i)
{
    if(边界)
    {
        输出解;
    }
    尝试每一种可能{
		if(满足进一步搜索条件)
    	{
    		标记;
            dfs(i+1);
        	回溯; 
    	}
	}                
}

2.凑算式
在这里插入图片描述
这个算式中A-I代表1~9的数字,不同的字母代表不同的数字。比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?

思路:在1~9的全排列中找符合条件的等式

#include<iostream>
using namespace std;
int ans=0,num[9];//ans=答案 
int v[10];//标记是否使用过 
void judge(){//判断条件 
    if((num[0]+(double)num[1]/num[2]+(double)(num[3]*100+num[4]*10+num[5])/(num[6]*100+num[7]*10+num[8]))==10)
        ans++;
    return;
}
void dfs(int i){//i为num[]的第i位 
    if(i==8+1){//i==8+1表示num数组中的前8个已经放置好数字 
        judge();
        return;
    }
    for(int j=1;j<10;j++){
        if(v[j]==0){//判断数字是否使用过 
            v[j]=1;
            num[i]=j;
            dfs(i+1);//进行下一个数字的放置 
            v[j]=0;//回溯,当满足一种全排列后,进行下一种尝试
        }
    }
}
int main(){
    dfs(0);
    cout<<ans<<endl;
return 0;
}

3.六角填数
在这里插入图片描述
如图所示六角形中,填入1~12的数字。
使得每条直线上的数字之和都相同。
图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?
答案:10

#include <iostream>
using namespace std;
int v[13],a[13]; //v[]标记1~12有没有被使用过,a[]标记12个位置所对应的数
int line[6]; //表示各条线的和 
int judge(){//判断每条直线上的数字之和是否都相同
	line[0]=a[1]+a[3]+a[6]+a[8];
    line[1]=a[1]+a[4]+a[7]+a[11];
    line[2]=a[8]+a[9]+a[10]+a[11];
    line[3]=a[2]+a[3]+a[4]+a[5];
    line[4]=a[2]+a[6]+a[9]+a[12];
    line[5]=a[5]+a[7]+a[10]+a[12];
    int i; 
    for(i=1;i<=5; i++) {
        if(line[i]!=line[i-1])
            return 0;
    }
    return 1;
} 
void dfs(int x){
    int j;
    if(x==1 || x==2 || x==12){//已知条件则跳过搜索下一个
        dfs(x+1);
        return ;
    }
    if(x==12+1){//前12个数已经填满 
        if(judge()==1)//若满足条件,则输出a[6]的值
        	cout<<a[6]<<endl;
        return ;
    }
    for(j=1;j<=12;j++){//从1开始找没使用过的数字 
        if(v[j]==0){
            v[j]=1;//标记 
            a[x]=j;//当前位置存放未使用的数字 
            dfs(x+1);//进行下一个位置的数字放置 
            v[j]=0;//回溯 
        }
    }
}
int main(){
    //根据题意初始化值
    v[1] = 1;
    v[3] = 1;
    v[8] = 1;
    a[1] = 1;
    a[2] = 8;
    a[12] = 3;
    dfs(1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凝聚细沙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值