深度优先遍历(DFS)

是什么?

深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法。使用递归可以很好的实现深度优先遍历,因此,只能说递归是实现深度优先遍历的一种实现方式。

解决问题

给定一个序列,枚举这个序列所有的子序列
例如{1,2,3}子序列包含{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}
选择最优子序列,使它的某个特征是所有子序列中最优的。
这个问题也就是从n个整数中,选择k个数的所有方案。

应用一

N件物品,重量w[i],价值c[i],选出若干,使总重量不超过V,找出价值最大的值

思路

使用DFS遍历判断
结束条件,所有的可能序列遍历一遍
岔路口分支:选择当前物品,或者不选择当前物品。

代码

#include<stdio.h>
const int maxn = 20;
int w[maxn],c[maxn];
int n,V;
int maxc = 0;
void DFS(int index,int sumW,int sumC){
	if(index == n){
		if(sumW <= V && sumC > maxc){
			maxc = sumC;
		}
		return ;//即使不是最大的maxc也要return 出去 
	}
	DFS(index + 1 ,sumW,sumC);
	DFS(index + 1 ,sumW+w[index],sumC+c[index]) ;//注意下标的差1 
}
int main() {
	scanf("%d %d",&n,&V);
	for(int i = 0; i<n; i++) {
		scanf("%d",w+i);
	}
	for(int i = 0; i<n; i++) {
		scanf("%d",c+i);
	}
	DFS(0,0,0);
	printf("%d\n",maxc);
	return 0; 
}

在这里插入图片描述

改进(剪枝)
原先直接加入当前物品,也不管不顾是否已经超出了总重量,
现在在加入之前,提前加入判断条件

#include<stdio.h>
const int maxn = 20;
int w[maxn],c[maxn];
int n,V;
int maxc = 0;
void DFS(int index,int sumW,int sumC) {
	if(index == n) {
		return ;//即使不是最大的maxc也要return 出去
	}
	DFS(index + 1 ,sumW,sumC);
	if(sumW+w[index] <= V) {
		if(sumC+c[index]>maxc)
			maxc = 	sumC+c[index];
		DFS(index + 1 ,sumW+w[index],sumC+c[index]) ;//注意下标的差1
	}
}
int main() {
	scanf("%d %d",&n,&V);
	for(int i = 0; i<n; i++) {
		scanf("%d",w+i);
	}
	for(int i = 0; i<n; i++) {
		scanf("%d",c+i);
	}
	DFS(0,0,0);
	printf("%d\n",maxc);
	return 0;
}

应用二

N个整数中选择k个数,使得整数和恰好等于给定的整数x,如果有多种方案,选择平方和最大。

这里加入了如何存储最优方案,先用一个temp用来存放该过程的一个序列,如果是当前最优,则交给ans

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn = 20;
int w[maxn];
int n,k,x;
int maxseq = 0;
vector<int> temp,ans;
void DFS(int index,int nowk,int sum,int sumseq) {//存放当前位置,当前包含的数量,当前和数,平方和数 
	if(nowk == k&&sum == x) 
	{
		if(sumseq > maxseq ){
			maxseq = sumseq;
			ans = temp;
		}
		return ;//即使不是最大的maxc也要return 出去
	}
	if(index == n||nowk> k ||sum > x){
		return;
	}
	//选择当前的
	temp.push_back(w[index]); 
	DFS(index + 1 ,nowk + 1,sum +w [index],sumseq + w[index] * w[index]);
	temp.pop_back();
	DFS(index + 1 ,nowk ,sum ,sumseq) ;//不选择 
	}


int main() {
	scanf("%d %d %d",&n,&k,&x);//n个数选择k个使和为x 
	for(int i = 0; i<n; i++) {
		scanf("%d",w+i);//输入n个数 
	}
	DFS(0,0,0,0);
	for(auto it = ans.begin();it!=ans.end();it++){
		printf("%d ",*it);
	}
	printf("\n");
	printf("%d\n",maxseq);
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值