算法提高之金明的预算方案
-
核心思想:有依赖的背包dp + 分组背包
- 状态表示f[i,j]: 考虑前i个组,总体积不超过j的方案
- 状态计算:f(i,j)=max(f(i−1,j),f(i−1,j−vk+wk))
- 遍历每种取附件的方案
-
#include <iostream>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int N = 65 , M = 32010;bool is_aff[N];int f[M],v[N],w[N];vector<int> aff[N];int n,m;void dp(int u,int j){int siz = aff[u].size(); //取附件个数for(int st=0;st<1<<siz;st++) //二进制遍历每一种取附件的情况{int v_sum = v[u]; //取附件之前先取主件int w_sum = w[u];for(int i=0;i<siz;i++) //遍历图中每一位 看看是不是取了{if(st>>i & 1){v_sum += v[aff[u][i]];w_sum += w[aff[u][i]];}}if(j>=v_sum) f[j] = max(f[j],f[j-v_sum] + w_sum); //取完所有附件 当前组的花费和价值}}int main(){cin>>m>>n;for(int i=1;i<=n;i++){int fa;cin>>v[i]>>w[i]>>fa;w[i] *= v[i];if(fa) aff[fa].push_back(i); //分组存入编号为fa的组else is_aff[i] = true; //标记编号为i的物品为主件}for(int i=1;i<=n;i++)if(is_aff[i]) //如果是主件for(int j=m;j>=0;j--) //做01背包dp(i,j);cout<<f[m]<<endl;return 0;}