背包问题的分支界限算法

背包问题,分支界限算法

注释和思路都在代码里了。。

递归+剪枝优化

背包问题的分支界限算法

分支界限,就是根据条件来剪枝,条件边界就叫做界,求是否满足条件的过程就叫作代价函数

不能直接copy代码的

代码

#include<bits/stdc++.h>
using namespace std;

int n; //物品数量 
int limitWeight; //背包上限重量 
const int maxn = 1010;
int bestValue = 0; //最优值 背包能装的最大价值 

//物品node 两个属性 价值 和 重量 
struct node{
    int v;
    int w;
};

//定义排序规则 
bool cmp(node a,node b){
    double flag1 = a.v*1.0/a.w;
    double flag2 = b.v*1.0/b.w;
    return flag1 > flag2; //按价值与重量比排序 
}

struct node nod[maxn];//存放物品的结构体数组 
int takeNum[maxn]; //记录拿物品的数量 
int bestTake[maxn]; //记录最优的 拿物品的数量 

//第x个物品时 当前背包的重量 code by:fishers 
void dfs(int x,int curWeight,int curValue){
    
    if(x == n+1){ //递归出口 拿第x+1个物品了 就是到达了叶节点 
        if(curValue > bestValue && curWeight <= limitWeight){
            bestValue = curValue; //更新最优值 
            for(int i=1;i<=n;i++) bestTake[i] = takeNum[i];
        }
        return; //结束递归 
    }
    
    int nextMaxValue = curValue + (limitWeight - curWeight)*(nod[x].v/nod[x].w); //分支界限: 以后最大也就是用背包剩下的重量全拿这个物品x(因为之前按重量价值比排序啦,小贪心) 
    if(nextMaxValue < bestValue) return; //和最优值(已经搜索出的背包最大价值)比较(剪枝优化),小于最优值就直接返回了  
    
    int curMaxNum = (limitWeight - curWeight)/nod[x].w; //当前一层最多拿物品x的个数 (以确保不超过最大背包重量上限limitWeight) 
    for(int i=curMaxNum;i>=0;i--){ //枚举每一个分支 i表示拿这个物品的个数:拿i个 
        int nextWeight = curWeight + i * nod[x].w; //如果这一次拿了i个物品 算出nextWeight重量 上一轮重量+这一轮i个物品x的重量 
        if(nextWeight > limitWeight) continue;
        int nextActualValue = curValue + i * nod[x].v; //拿了i个物品后实际的价值 
        takeNum[x] = i; //记录第x个物品 拿的个数i 
        dfs(x+1,nextWeight,nextActualValue); //递归搜索下一个 物品的情况 
        takeNum[x] = 0;
    }
}

void input(){
    cin>>n>>limitWeight; //输入物品个数n,背包承受的重量上限 
    for(int i=1;i<=n;i++) cin>>nod[i].v; //输入每个物品的价值 
    for(int i=1;i<=n;i++) cin>>nod[i].w; //输入每个物品的重量 
    sort(nod+1,nod+n+1,cmp); //把物品按 价值重量比 排序 (贪心,也是后面分支界限来剪枝的前提) 
}

int main(){
    input();
    
    dfs(1,0,0);
    
    cout<<"背包最多装的价值是"<<bestValue<<endl;
    for(int i=1;i<=n;i++) {
        cout<<"拿了"<<bestTake[i]<<"个"<<"重量为"<<nod[i].w<<",价值为"<<nod[i].v<<"的物品."<<endl;
    }
    return 0;
} 

/*
4 10
1 3 5 9
2 3 4 7
*/

运行结果是这个样子

背包问题的分支界限算法

不能直接copy

上一篇:洛谷 P2824 [HEOI2016/TJOI2016]排序


下一篇:求树的某一层的节点最多