(模板)深度优先遍历与背包问题

深度优先算法除了可以解决图遍历问题,还可以解决背包问题,主要思想是遇到岔路:选还是不选

比如背包问题:

对于每件物品都有选或者不选两种情况,好比迷宫中的岔路,这时候我们可以利用深度优先算法思想遍历出所有的情况,然后选择不超过V的同时物品价值最大的情况

void DFS(int index, int sumW, int sumC) {
	//递归到界限的话,退出循环
	if (index == n) {
		if (sumW + w[index] <= V && sumC + c[index] > maxValue) {   //剪枝部分
		      maxValue = sumC + c[index];
          }
          return;
	   }
	   DFS(index+1, sumW, sumC); 
	   DFS(index + 1, sumW + w[index], sumC + c[index]); 
	}
}

这样的话我们把所有的情况遍历了一遍,时间复杂度为O(2^n)

我们可以继续优化,只有在当前重量<V时才进入岔道,这样可以省去部分没有用的道路,降低时间复杂度

const int MAXN = 30;
int n, V, maxValue = 0;
int w[MAXN], c[MAXN];

void DFS(int index, int sumW, int sumC) {
	//递归到界限的话,退出循环
	if (index == n) {
		return;
	}
	DFS(index+1, sumW, sumC); //先选择不选
	if (sumW + w[index] <= V) {   //剪枝部分
		if (sumC + c[index] > maxValue) {
			//更新最大质量
			maxValue = sumC + c[index];
		}
		DFS(index + 1, sumW + w[index], sumC + c[index]);  //选
	}

另外一种背包问题的题型也可以用深度优先算法解决

给定N个整数(有可能有负数),从中选择K个数,使得这K个数之和恰好等于一个给定的整数X,如果有多种方案,选择它们中元素平方和最大的那一种

对于每一个数,有选或者不选两种方案,即两条岔路

我们可以定义一个vector,执行选方案时,将选的数push入vector,然后判断是否达到条件

如果没有达到条件,则将这个数弹出vector,然后执行不选的方案

int n,k,x,maxSumSqu = -1,A[maxn];
vector<int> temp,ans;
void DFS(int index, int nowK, int sum, int sumSqu){
    if(nowK == k && sum == x){
       if(sumSqu > maxSumSqu){
           maxSumSqu = sumSqu;
           ans = temp;
       }
       return;
    }

    if(index == n || nowK > k || sum > x) return;
     
    temp.push_back(A[index]);
    DFS(index+1, nowK+1, sum+A[index], sumSqu+A[index]*A[index]);
    temp.pop_back();
    DFS(index+1, nowK, sum, sumSqu);
}

如果同一个数可以被重复选择的话,只需把

DFS(index+1, nowK+1, sum+A[index], sumSqu+A[index]*A[index]);

改成

DFS(index, nowK+1, sum+A[index], sumSqu+A[index]*A[index]);

具体问题:https://blog.csdn.net/alex1997222/article/details/86580252

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * (有向)图的深度优先遍历算法模板 */ package dsa; public abstract class DFS extends GraphTraverse { //变量 protected static int clock = 0;//遍历过程中使用的计时钟 //构造方法 public DFS(Graph g) { super(g); } //深度优先遍历算法 protected Object traverse(Vertex v, Object info) {//从顶点v出发,做深度优先查找 if (UNDISCOVERED != v.getStatus()) return null;//跳过已访问过的顶点(针对非连通图) v.setDStamp(clock++); v.setStatus(DISCOVERED); visit(v, info);//访问当前顶点 for (Iterator it = v.outEdges(); it.hasNext();) {//检查与顶点v Edge e = (Edge)it.getNext();//通过边e = (v, u) Vertex u = (Vertex)e.getVPosInV(1).getElem();//相联的每一顶点u switch (u.getStatus()) {//根据u当前的不同状态,分别做相应处理 case UNDISCOVERED ://若u尚未被发现,则 e.setType(TREE);//e被归类为“树边” traverse(u, info);//从u出发,继续做深度优先查找 break; case DISCOVERED ://若u已经被发现,但对其访问尚未结束,则 e.setType(BACKWARD);//将e归类为“后向跨边” break; default ://VISITED,即对u的访问已经结束 if (u.getDStamp() < v.getDStamp())//若相对于v,u被发现得更早,则 e.setType(CROSS);//将e归类为“横跨边” else//否则 e.setType(FORWARD);//将e归类为“前向跨边” break; } }//至此,v的所有邻居都已访问结束,故 v.setFStamp(clock++); v.setStatus(VISITED);//将v标记为VISITED return null;//然后回溯 } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值