本文主要是介绍codeforces 364B Free Market dp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题意:有n个品种的物品,每个物品的价格为c[ i ],每次你可以从你拥有的物品中挑取部分去商店去兑换。兑换有如下限制:
(1)你拿去兑换的物品(不妨设拿去兑换的物品集合为s),都要换成集合s所没有的。比如(a,b)--->(v,a)就是不合法的
(2)你拿去兑换的物品集s1里的价值和cost1与你兑换回来的物品集s2里的价值和cost2需要满足:cost1+d>=cost2
每天你只能去兑换一次。
问通过兑换可以获得的物品集价值和的最大值以及所需的兑换天数
思路:我们用dp记录当前价值和是否可达。然后每次贪心找满足增值<=d可以到达的最大状态。不妨设当前状态为a,可到达的最大状
态一定满足 a+d>=b,那么一定可以从a状态转移到b。
(1)如果a,b没有交集,那么直接把所有商品拿去兑换成b状态的商品。
(2)如果a,b有交集,那么之需要不把相交的部分拿去兑换就好。
详见代码:
// file name: codeforces364B.cpp //
// author: kereo //
// create time: 2014年08月24日 星期日 17时43分27秒 //
//***********************************//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=600000+100;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
int n,d;
int dp[MAXN];
int main()
{while(~scanf("%d%d",&n,&d)){int sum=0;memset(dp,0,sizeof(dp));dp[0]=1;for(int i=1;i<=n;i++){int x;scanf("%d",&x); sum+=x;for(int j=sum;j>=x;j--) if(dp[j-x])dp[j]=1;}int st=0,ans=0;while(1){st+=d;//这一次的状态上限int pos=d;for(int i=0;i<d;i++) if(dp[st-i]){ //该次最大可到达的状态pos=i; break;}if(pos == d) {st-=d; break;}st-=pos;ans++;}printf("%d %d\n",st,ans);}return 0;
}
这篇关于codeforces 364B Free Market dp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!