原題:
E. Knapsack
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You have a set of items, each having some integer weight not greater than 8. You denote that a subset of items is good if total weight of items in the subset does not exceed W.
You want to calculate the maximum possible weight of a good subset of items. Note that you have to consider the empty set and the original set when calculating the answer.
Input
The first line contains one integer W (0≤W≤10^18) — the maximum total weight of a good subset.
The second line denotes the set of items you have. It contains 8 integers cnt1, cnt2, …, cnt8 (0≤cnti≤10^16), where cnti is the number of items having weight i in the set.
Output
Print one integer — the maximum possible weight of a good subset of items.
Examples
input
10
1 2 3 4 5 6 7 8
output
10
input
0
0 0 0 0 0 0 0 0
output
0
input
3
0 4 1 0 0 9 8 3
output
3
中文:
給你8個物品,這8個物品的價值是分別是1到8,每個物品的數量對應爲到,給你一個容量爲W的揹包,現在問你最多能得到多少價值?(W超大)
代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 840;
ll W,a[9],cnt[9];
int dp[9][N*8+1];
int main()
{
ios::sync_with_stdio(false);
while(cin>>W)
{
ll ans=0,tot=0,tmp=0,res=0;
memset(dp,0,sizeof(dp));
for(ll i=1;i<=8;i++)
{
cin>>a[i];
tot+=a[i]*i;
cnt[i]=min(a[i],N/i);
a[i]-=cnt[i];
}
if(tot<=W)
{
cout<<tot<<endl;
continue;
}
if(W-N>0)
tmp=W-N;
ll val;
for(ll i=1;i<=8;i++)
{
val=min(a[i],(tmp-res)/i);
res+=val*i;
}
dp[0][0]=1;
for(int i=1;i<=8;i++)
{
for(int j=0;j<=N*8;j++)
{
for(int k=0;k<=cnt[i];k++)
{
if(j-i*k>=0)
dp[i][j]|=dp[i-1][j-i*k];
}
}
}
for(ll i=W-res;i>=0;i--)
{
if(dp[8][i])
{
ans=res+i;
break;
}
}
cout<<ans<<endl;
}
return 0;
}
思路:
由於揹包的容量和每樣物品給定的數量巨大,不可能直接用多重揹包或搜索直接求解。那麼可以考慮講W分成兩個部分和,其中較大的部分使用貪心的方法解決。剩餘的部分使用多重揹包的方式解決。
由於物品的種類和價值只有固定的8種,對應1到8,物品價值和種類相同,且只有8種,可以求得1到8的最小公倍數爲840,840可以任意整除1到8種的任意數字。
以840作爲的初始值,初始值的意思是這樣,因爲對進行貪心求解,不一定正好得到的使得貪心的結果使得正好裝滿。
首先將每種物品的數量分成兩份,分別爲和,有關係如下
用作可以放在種使用多重揹包求解的每個物體數量
由於數量較大(當很大時),將這部分物體直接用貪心的方法解決。
使用貪心的方式計算得到的最大價值不一定正好填滿,記錄此時裝入物體的臨時結果,並此時更新與
由於新的很有可能大於840,極端情況下就是剩餘了8*840容量,此時可用多重揹包對剩餘的容量進行計算,得到最優值,與前面得到的臨時結果相加即可
這題曾經在UVa上做過類似的,當年秒出的題,時間長了居然看了半天題解才明白=_=