CSP-J 2019 T3 纪念品

(mathfrak{a}).反思:

通过这道题成功发现自己的背包还是很差(w)

可能这是我(gu)了好久好久博客的报应

就在做这个题的时候,自己连背包(dp)的思想都忘了

背包可以说是最早接触的(dp)了,还记得自己(CSP)之前他们讲背包,自己是真的忘记了。

可以说是在(dp)的洪流中忘本了吧

(mathfrak{b}. Solution)

其实是一个蛮显眼的多次完全背包问题,但思路受限于纪念品的卖出和买进。

第一想法是用一个数组(NT[])在更新的时候记录下每种物品的数量,乱七八糟状态爆炸(color{gold}{Boom!})

题目中有一句话还是挺关键的:

“每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币”

这也就提示我们可以当天买的纪念品在第二天卖出,如果并不打算在第二天卖出的话,显然我们可以把它再买回来((wonderful!)

然而我并没有那个敏感。

这样就省去了记录(NT[])数组的状态表达;

对每天做一次完全背包(day 1 o T),设(dp[j])表示当天恰好花费(j)元时获得的最大收益,把某件物品的价格看做体积,把这一天买入,第二天卖出的所收获的"差价"看做是价值,转移方程:

(dp[j]=max {dp[j-cost_{day,i}]+cost_{day+1,i}-cost_{day,i},j>=cost_{day,i}}),其中(cost_{a,b})表示第(a)天第(b)件物品的价格.

每天做完背包以后取最大的(dp[j]),更新下一天初始拥有的钱数(贪心的想:当我们某天拥有的钱数最多的时候,最终解最优)

(mathfrak{c}.Code:)

#include<bits/stdc++.h>

using namespace std;

inline int read() {
	int ans=0;
	char last=' ',ch=getchar();
	while(ch>'9'||ch<'0') last=ch,ch=getchar();
	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
	if(last=='-') ans=-ans;
	return ans;
}

int P[110][110];
int NT[110];
int dp[101000];

int main() {
	int T,M,N;
	T=read();
	N=read();
	M=read();
	for(int i=1;i<=T;i++) 
		for(int j=1;j<=N;j++) 
			P[i][j]=read();
	int MAxn;
	for(int d=1;d<=T;d++) {
		MAxn=-0x9f9f9f9;
		dp[0]=M;
		for(int i=1;i<=N;i++) {
			for(int j=P[d][i];j<=M;j++) 
				dp[j]=max(dp[j],dp[j-P[d][i]]-P[d][i]+P[d+1][i]);
		}
		for(int j=0;j<=M;j++) 
			MAxn=max(MAxn,dp[j]);
		M=MAxn;
	}
	printf("%d",M);
	return 0;
}

双倍经验的快乐(s* lz把数组大小开反了然后快乐RE+WA P2938

原文地址:https://www.cnblogs.com/zhuier-xquan/p/12079009.html