[ZOJ 3049] Diablo II Items [动态规划]

本文介绍了一种基于动态规划的方法来解决装备售卖问题。通过对比直接售卖与鉴定后售卖的收益,利用DP算法寻找最优策略,确保资金始终为正的同时最大化最终收益。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

你身上有一批装备,有一部分只能直接卖,有一部分既可以直接卖又可以用鉴定卷轴鉴定后再卖。现在告诉你所有的装备卖出去的价钱,以及鉴定卷轴的价钱,以及那些可以鉴定的装备鉴定后的价钱。鉴定卷轴是一次性的,再用还得在买。并且你不能赊账,即你在任意时刻钱都要大于零。你最开始没有任何钱。问你把所有装备都卖了能够得到的最大价钱。

首先我们可以把所有的直接卖比较好的物品都直接卖了,作为初始资金。其余物品用鉴定后价钱减去卷轴价钱作为鉴定后收益。这样只要我们不用鉴定卷轴卖的物品达到了鉴定卷轴的价钱,我们就能够得到剩余所有物品的鉴定后收益。

然后定义状态dp[i][j]表示假定已经有了鉴定卷轴,前i个剩余的物品中,不用鉴定卷轴直接卖的物品总共卖了j元钱,能够得到的最多的总收益。若j大于鉴定卷轴的钱,则可以统一置成鉴定卷轴的价钱。

#include <cstdio>
#include <cstring>

inline void in(int &x,int &y) {
	char c=getchar();
	x=y=0;
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') {
		x=x*10+c-'0';
		c=getchar();
	}
	while (c<'0'||c>'9') {
		if (c=='\n') return;
		c=getchar();
	}
	while (c>='0'&&c<='9') {
		y=y*10+c-'0';
		c=getchar();
	}
}

int n,m,newn,sum;
int a[1000];
int b[1000];
int dp[1001];

inline void update(int &a,int b) {
	if (b>a) a=b;
}

int main() {
	int i,j;
	while (scanf("%d%d",&n,&m)!=EOF) {
		getchar();
		sum=newn=0;
		for (i=0;i<n;i++) {
			int x,y;
			in(x,y);
			if (x>=y-m) {
				sum+=x;
			} else {
				a[newn]=x;
				b[newn]=y-m;
				newn++;
			}
			//printf("%d %d\n",x,y);
		}
		n=newn;
		for (i=0;i<=m;i++) dp[i]=-1;
		if (sum<m) dp[sum]=sum;
		else dp[m]=sum;
		for (i=0;i<n;i++) {
			sum+=a[i];
			if (dp[m]!=-1)
				update(dp[m],dp[m]+b[i]);
			for (j=m-1;j>=0;j--) {
				if (dp[j]!=-1) {
					if (j+a[i]<m)
						update(dp[j+a[i]],dp[j]+a[i]);
					else 
						update(dp[m],dp[j]+a[i]);
					update(dp[j],dp[j]+b[i]);
				}
			}
		}
		if (dp[m]==-1) printf("%d\n",sum);
		else printf("%d\n",dp[m]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值