Codeforces 364B 双肩包+贪心
Codeforces 364B 背包+贪心
题目链接:http://codeforces.com/problemset/problem/364/B
给定n个物品(每个物品只有1件,d值)
每次可以用手头的物品(设价值为val)换取不在手头的物品(任意件数,总价值要<=val+d)
问能换到的最大价值及在此价值下的最小次数。
思路:
先背包一下跑出所有可能换到的价值,然后贪心一直增加价值直到不能增加。
证明贪心:
对于当前集合x,要变成集合y
首先: (x)+d >= y
那么并不需要关心集合 x,y 是否有交集
如果有交集z,则z这个集合不参与更换即可,因为z换z没啥意义,也不合法。
那么剩下的就是x的 x' 换成 y的y',显然 x'∩y' = 空集
所以贪心地增加价值合法。
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace std; #define N 1234567 #define ll __int64 ll n,d; ll a[55]; ll dp[N]; int main(){ ll i, j; while(~scanf("%I64d %I64d",&n,&d)){ memset(dp, 0, sizeof dp); ll sum = 0; for(i = 1; i <= n; i++)cin>>a[i], sum+=a[i]; dp[0] = 1; for(i = 1; i <= n; i++) { for(j = N-a[i]-1; j>=0; j--) { if(dp[j]) dp[j+a[i]] = 1; } } ll ans = 0, step = 0; while(1){ for(j=ans+d;j>ans;j--) if(j<=sum&&dp[j]) break; if(j==ans)break; ans = j;step++; } cout<<ans<<" "<<step<<endl; } return 0; }