2020-09-06 深度优先搜索学习

深度优先搜索练习

关于凑数 (参考书目《啊哈!算法》)

从1-9共9张扑克牌中放到9个盒子里,并使得____+____=____成立(每个下划线上填一个三位数)

#include<stdio.h>
int a[10],book[10],total;
//这里还有需要注意的地方C语言全局变量默认为0

void  dfs(int step){ 
	int i;
	if(step==10)//设立终止点
	{ 
		if(a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]==a[7]*100+a[8]*10+a[9]){
			total++;
			printf("%d%d%d+%d%d%d=%d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
		} 	
	return ;   
}		
	 for(int i=1;i<=9;i++){
		if(book[i]==0){  //说明i号扑克牌还在手里,需要放入step号盒子
			a[step]=i;//将i号扑克牌放到第step个盒子中
			book[i]=1;//此时i号扑克牌已经被使用		
			dfs(step+1);
			/*注意这里是自己调用自己,表示此时走到了第step+1个盒子面前*/
			//并且step在下一步中每次调用都会自动加1		
			book[i]=0;
			/*book[i]=0表示dfs调用结束了,换句话说就是扑克牌已经全部放完了
			  需要按照顺序将扑克牌收回,重新放,也就是前面所说的
			 */
		}
	}
	return;//这里表示这一级别的dfs函数已经结束了,返回上一级 dfs函数 

}
int main(){
	dfs(1);   //dfs函数的开始 
	printf("%d",total/2);
	//之所以除以2是因为会出现173+286=459和286+173=459是同一种解的情况
	return 0;
}

为了更方便的理解,我们可以尝试先自己先演示一次。例如:123+456=789,显然是不成立的。程序会直接return,退回上一级,即123+345=78_,而此时循环已经结束,所以又会退回更上一级,123+456=7__。本轮中 i 此时等于8,循环进入下一级,i=9, 此时123+456=79_。执行dfs(9),得到123+456=798。不成立,按照上述步骤继续重复往更上一级后退 。

有了上面的经验,我们继续进行下一道题

求部分和

给定质整数a1,a2,…an,判断是否可以从中选出若干数,使他们的和恰好为k.
样例输入:
n=4, k=13 a={1,2,4,7}
输出
YES
2,4,7
输入
n=4, k=15 a={1,2,4,7}
输出
NO

#include<stdio.h>
#include<string.h>
int a[30],book[30];// book[i]用来判断a[i]是否使用了 
int n,s,sum,judge,judgeT;//全局变量默认为0 
void dfs(int step)
{
    int i;
     if(s==sum)
        {
            judge=1;
                printf("YES\n");
                for(i=0; i<n; i++)
                    if(book[i])
                        printf("%d ",a[i]);
                printf("\n");
                return;
        } 
    if(s>sum){
    	judgeT=1;
		//减少运算量 
	}
    int  num;
    if(judgeT==0){ 
    	for(num=step; num<n; num++)
    	{
        	s=s+a[num];
       		book[num]=1;
			dfs(num+1);//这个与上一题不一样的地方在于可能会出现num+1之后大于n的情况,但是不影响程序运行 
        	s= s-a[num];//当程序运算到这一步说明并未出现s==sum的情况,s的值需要退回上一级。 
        	book[num]=0;
        	judgeT=0;
    	}
    } 
}
int main(void)
{
    int i;
    while(~scanf("%d%d",&n,&sum))//~scanf等效于scanf()!=EOF。没有输入的时候自动退出。 
    {
        judge=0;
        memset(book,0,sizeof(book));
         //将所有book[]都设置为0 ,这段代码纯画蛇添足(我只是用来复习一下memset)
        for(i=0; i<n; i++)
            scanf("%d",&a[i]);
        dfs(0);
        if(judge==0) printf("NO\n");
    }
    return 0;
}

这道题的关键是在于不是所有输入的数字都会被最终使用,所以这道题的判断终止标准与上一道题截然不同。我觉得只需要在每次调用dfs时使用return语句即可(目前我没有看出来有什么不妥当的地方)。本题中我认为最关键的一步思考是在于s= s-a[num]; 同时judgeT用来减少计算量也是很重要的一步。
`

总结:

深度优先搜索重点在于思考“当前情况下如何去做”,至于“下一步如何去做”则与“当前情况下如何去做”有着共同之处
深度优先搜索基本模型

void dfs(int step){
	判断边界(可以灵活调整判断边界代码的位置但是必须要有)
	通用型尝试每一种可能 for(i=0;i<n;i++){
		继续下一步 dfs(step+1)
	}
	return;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值