原题:
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上做过类似的,当年秒出的题,时间长了居然看了半天题解才明白=_=