背包問題,分支界限算法
注釋和思路都在代碼里了。。
這里的背包問題,就是完全背包,可以無限次拿同一種物品的那種
遞歸+剪枝優化

分支界限,就是根據條件來剪枝,條件邊界就叫做界,求是否滿足條件的過程就叫作代價函數
代碼
#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
*/
運行結果是這個樣子
