1. 程式人生 > >2018.11.09【NOIP2006】【洛谷P1064】金明的預算方案(有依賴的揹包問題)

2018.11.09【NOIP2006】【洛谷P1064】金明的預算方案(有依賴的揹包問題)

傳送門


解析:

首先我並沒有讀完題。。我也沒有管什麼只有兩個依賴,,我直接寫的最裸的單層依賴的揹包問題。。。(其實依賴下面套分組還比這個要噁心)。

思路:

由於我們直接列舉所有策略,對於一個物品集合是 O ( 2 S

) O(2^{|S|}) 的,所以我們可以先在集合內部做一次 01 01 揹包,注意,為了減小最終的物品個數,可以使用恰好揹包。

然後就是集合與集合之間的分組揹包裸題了。


程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

cs int N=65,M=32004;
vector<pair<int,int> > vec[N];
vector<pair<int,int> > item[N];
int v[N],p[N],q[N];
int f[M];
int n,
m; signed main(){ scanf("%d%d",&n,&m); for(int re i=1;i<=m;++i){ scanf("%d%d%d",&v[i],&p[i],&q[i]); if(q[i]){ vec[q[i]].push_back(make_pair(v[i],p[i])); } } for(int re i=1;i<=m;++i){ if(!vec[i].empty()){ memset(f,-1,sizeof f); f[0]=0; for(int re j=0;j<vec[i].size();++j){ for(int re k=n-v[i];k>=vec[i][j].first;--k){ if((~f[k-vec[i][j].first])&&f[k]<f[k-vec[i][j].first]+vec[i][j].first*vec[i][j].second){ f[k]=f[k-vec[i][j].first]+vec[i][j].first*vec[i][j].second; } } } for(int re k=n-v[i];k;--k){ if(~f[k]){ item[i].push_back(make_pair(k+v[i],f[k]+v[i]*p[i])); } } } if(!q[i]){ item[i].push_back(make_pair(v[i],v[i]*p[i])); } } memset(f,0,sizeof f); for(int re i=1;i<=m;++i) for(int re k=n;k;--k) for(int re j=0;j<item[i].size();++j) if(k>=item[i][j].first)f[k]=max(f[k],f[k-item[i][j].first]+item[i][j].second); cout<<f[n]; return 0; }