極大容量的完全背包問題


題目大意:

就是題目名稱的意思,有n種物品,一個容量為m的背包,每種物品的體積為$ a_i $,價值為$ b_i $,有$ n<=10^6,m<=10^{18},a_i,b_i<=100 $。求最大價值。

解題方法:

因為m很大,所以我們考慮將較大的體積為S的背包分為較小的兩個背包,其中一個體積為x,則另一個S-x。

這時討論abs(x-(S-x))的范圍,可以推出其<=maxv(物品的最大體積)。因為單獨對兩個背包操作,兩邊會有余留下來的部分,將其中一個余留下來的部分補到另一個去可能會得到更憂解。但如果移動的部分大於maxv了則放在兩個背包中的任意一個都可以得到最優解。所以我們成功將枚舉區間縮小到了$ \frac{S-maxv} {2} <=x<= \frac{S+maxv} {2} $。

然后我們類似分治的套路將圖畫出來:

發現$ Max -Min < 2\times maxv $並且最底層(即$ Min>0 $的最后一層)的$ Min <= maxv,Max<=3 \times maxv $,所以我們可以預處理出$ 3\times maxv $大小的背包就可以得到最底層的解,然后我們可以記錄每層最小值$ L[i] $即最左邊的點的權值,設$ g[i][j] $表示在第i層時比$ L[i] $容量大j的背包的最優解,枚舉x逐層向上轉移即可,轉移方程:$ g[i][v-L[i]]=max(g[i+1][x-L[i+1]]+g[i+1][v-x-L[i+1]]) $。

因為一開始給了$ 10 ^ 6$種物品,然而因為最多有$ 100\times 100 $種物品,所以可以用set去重。

代碼:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define del(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 const int MAXN=1e5+10;
 6 ll n,m,tot;
 7 set<int> ap[110];
 8 ll f[MAXN],g[55][MAXN],L[55],a[MAXN],b[MAXN];
 9 void Max(ll &a,ll b){a=(a>b? a:b);}
10 template <class T>void read(T &x)
11 {
12     bool f=0;char ch=getchar();x=0;
13     for(;ch<'0' || ch>'9';ch=getchar())if(ch=='-') f=1;
14     for(;ch>='0' && ch<='9';ch=getchar())x=x*10+ch-'0';
15     if(f) x=-x;
16 }
17 int main()
18 {
19     read(n);read(m);
20     ll maxv=0;
21     for(int i=1;i<=n;i++)
22     {
23         ll x,y;read(x);read(y);
24         if(ap[x].find(y)!=ap[x].end()) continue;
25         a[++tot]=x;b[tot]=y;ap[x].insert(y);
26         Max(maxv,a[tot]);
27     }
28     ll s=m,cnt=0;
29     while(s>0)
30     {
31         L[++cnt]=s;
32         s=(s-maxv)>>1;
33     }
34     for(int i=1;i<=tot;i++)
35     for(int v=a[i];v<=maxv*3;v++)
36         Max(f[v],f[v-a[i]]+b[i]);
37     for(int i=cnt;i>=1;i--)
38     for(ll v=L[i];v<=L[i]+maxv*2;v++)
39     {
40         if(v<=maxv*3) g[i][v-L[i]]=f[v];
41         else
42         {
43             for(ll x=(v-maxv)>>1;x<=v>>1;x++)
44             Max(g[i][v-L[i]],g[i+1][x-L[i+1]]+g[i+1][v-x-L[i+1]]);
45         }
46     }
47     printf("%lld",g[1][0]);
48     return 0;
49 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM