CF632E Thief in a Shop
题意
一个背包, 种物品,第 种物品价值为 ,每种物品无穷个,只能拿 个物品,问有哪些可能的价值?
分析
乍一看是一个完全背包模板,于是我们设 为当价值为 时最少需要的物品数,可以写出方程式 ,仅当 时,输出 。
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=1e6,inf=1010;
int n,k,a[N],dp[N*N];
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=M;i++)
dp[i]=inf;
for(int i=1;i<=n;i++)
for(int j=a[i];j<=M;j++)
dp[j]=min(dp[j],dp[j-a[i]]+1);
for(int i=0;i<=M;i++)
if(dp[i]==k)
cout<<i<<" ";
return 0;
}
然而连样例都过不了。
我们参考一下样例来找找原因:
3 2
1 2 3
原来在我们的计算里 ,但其实 也是可行的。
那么有没有什么办法可以把 个物品凑成 个物品呢?
我们假设有一个最好的情况,我们已选物品的价值加上其他物品的价值后总价值不变,但总数量却能涨到 个,在此样例中,设另外那个物品价值为 ,那么就相当于 ,即 。也就是说,我们只要有价值为 的物品,就可以凑成,可题目中 呀!
我们考虑之前的那个状态转移方程的变形:
若保证任意 ,则之前的转移方程为 ,设此时的某个答案为 ,则真正答案可以转化为 ,也就是把之前缺少的价值补回来。
了解了这个变形,我们只需取 ,就可以得到上面价值为 的物品。
于是我们就用新的状态转移方程求出 数组,只要 ,即需要的最少物品数不大于 个(缺少的可以用 补),就算作一个答案。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=1e6,inf=1010;
int n,k,a[N],dp[N*N],v=inf;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
v=min(v,a[i]);
}
for(int i=1;i<=M;i++)//预处理赋极大值
dp[i]=inf;
for(int i=1;i<=n;i++)//减去最小值
a[i]-=v;
for(int i=1;i<=n;i++)//普通完全背包
for(int j=a[i];j<=M;j++)
dp[j]=min(dp[j],dp[j-a[i]]+1);
for(int i=0;i<=M;i++)
if(dp[i]<=k)
cout<<i+k*v<<" ";
return 0;
}

浙公网安备 33010602011771号