P3188-[HNOI2007]梦幻岛宝珠【背包】
生活随笔
收集整理的這篇文章主要介紹了
P3188-[HNOI2007]梦幻岛宝珠【背包】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P3188
題目大意
nnn個物品,大小為WWW的背包。
每個物品的大小可以表示為wi=ai2biw_i=a_i2^{b_i}wi?=ai?2bi?,有價值viv_ivi?。
求選擇一些物品不超過背包的大小使得價值最大。
解題思路
設先計算bib_ibi?相同的物品,設fi,jf_{i,j}fi,j?表示只計算b=ib=ib=i的物品時,一個容量為j?2ij*2^{i}j?2i時的背包時的最大價值。
然后將多個背包合并,設gi,jg_{i,j}gi,j?表示只計算b≤ib\leq ib≤i的物品時,容量為j?2i+W&(2i?1)j*2^i+W\&(2^i-1)j?2i+W&(2i?1)時的最大價值。
然后有轉移方程gi,j=max{fi,j?k+gi?1,2k+(W>>(i?1))&1}g_{i,j}=max\{\ \ f_{i,j-k}+g_{i-1,2k+(W>>(i-1))\&1}\ \ \}gi,j?=max{??fi,j?k?+gi?1,2k+(W>>(i?1))&1???}
然后答案就是g30,0g_{30,0}g30,0?
時間復雜度O(nlog?a∑a)O(n\log a\sum a)O(nloga∑a)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=110; int n,W,a[N],v[N],lim[N]; int f[N][N*N],g[N][N*N]; vector<int> q[N]; int main() {while(1){ memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(lim,0,sizeof(lim));for(int i=0;i<=30;i++)q[i].clear(); scanf("%d%d",&n,&W);if(n==-1)return 0;for(int i=1;i<=n;i++){int b=0;scanf("%d%d",&a[i],&v[i]);while(a[i]>10 || !(a[i]&1))b++,a[i]/=2;q[b].push_back(i);lim[b]+=a[i];}for(int i=0;i<=30;i++)for(int j=0;j<q[i].size();j++)for(int k=lim[i];k>=a[q[i][j]];k--)f[i][k]=max(f[i][k-a[q[i][j]]]+v[q[i][j]],f[i][k]);for(int i=0;i<=lim[0];i++)g[0][i]=f[0][i];for(int i=1;i<=30;i++){lim[i]+=(lim[i-1]+1)/2;for(int j=0;j<=lim[i];j++)for(int k=0;k<=j;k++)g[i][j]=max(g[i][j],f[i][j-k]+g[i-1][min(lim[i-1],2*k+((W>>i-1)&1))]);}printf("%d\n",g[30][0]);} }總結
以上是生活随笔為你收集整理的P3188-[HNOI2007]梦幻岛宝珠【背包】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 视频怎么转音频mp3vivo视频怎么转音
- 下一篇: wifi路由器怎么开手机怎么关wifi路