P8548 小挖的买花 方法记录

原题链接

小挖的买花

题目背景

小挖喜欢买花,但是 ta 太懒了!所以这个任务全权交给了你。

题目描述

花店里只有 \(n\) 株花,每一株花都有三个属性:价格 \(cost_i\)、美丽度 \(be_i\)、新鲜程度 \(fr_i\)

小挖每次都有不同的要求。准确来说,对于第 \(j\) 次买花,你手里的钱至多能买下总价为 \(c_j\) 的花。同时,小挖还要求购买花的新鲜程度总和大于等于 \(f_j\)。而小挖希望知道,在满足 ta 给出的条件后,购买花的美丽度总和的最大值是多少?

小挖一共要让你买 \(q\) 次花,你能否正确回答 ta 的问题呢?

询问显然彼此独立。

输入格式

\(1\) 行,共两个数 \(n,q\)

\(2\sim n+1\) 行,每行三个数 \(cost_i,fr_i,be_i\),分别表示一株花的三个属性。

\(n+2\sim n+q+1\) 行,每行两个数 \(c_j,f_j\) ,表示每次买花时的要求。

输出格式

\(q\) 行,每行一个数,表示美丽度总和的最大值。

样例 #1

样例输入 #1

5 1
2 4 5
4 3 3
1 3 2
3 4 3
3 2 5
10 10

样例输出 #1

15

提示

对于 \(20\%\) 的数据,\(3\leq n,q\leq 16\)

对于 \(40\%\) 的数据,\(3\leq n,q\leq 30,0\leq c_j,f_j\leq 50\)

对于 \(60\%\) 的数据,\(3\leq n\leq 100,1\leq q\leq 5\times 10^4,0\leq cost_i,fr_i,c_j,f_j\leq 100\)

对于另外 \(20\%\) 的数据,对于每次买花,都有 \(f_j=0\)

对于 \(100\%\) 的数据,\(3\leq n\leq 500,\boldsymbol{1\leq q\leq 10^6},0\leq cost_i,fr_i,c_j,f_j\leq 500, 1\leq be_i \leq 10^6\)

审题

第一眼看到“费用”,“新鲜度”这两个指标,像极了二维费用的背包问题。不由得想到二维背包的经典例题:潜水员

但是本题和潜水员又有差别。因为潜水员一题中,两种付出代价的要求都是“至少”,即氧气、氮气都不能低于某一下限。而本题的特殊之处在于,指标“价格”要求不能超过上限,指标“新鲜度”不能低于下限。

思路

我们还是借用常规思想,用\(dp[i][j]\)来表示花费\(i\)的费用,在新鲜度为\(j\)的情况下,能获得的最大美丽度

状态转移方程

1.初始化:\(dp[i][j]=0\)

2.设计循环:

for(i=1~n,i++)//遍历花的种类
  for(j=c~cost[i],j--)//遍历价格
    for(k=f~0,k--)//遍历新鲜度

3.设计转移方程:

(1)若当前状态的新鲜度可以用第\(i\)种花卉直接满足,即\(k<=fr[i]\),则\(dp[j][k]=maxx(dp[j-cost[i]][0]+be[i],dp[j][k])\)

(2)若当前状态由上一个状态+第\(i\)种花卉转移过来,即\(dp[j-cost[i]][k-fr[i]]!=0\),则\(dp[j][k]=maxx(dp[j][k],dp[j-cost[i]][k-fr[i]]+be[i])\)

if(k<=fr[i])
{
  dp[j][k]=maxx(dp[j-cost[i]][0]+be[i],dp[j][k]);
}
else if(dp[j-cost[i]][k-fr[i]])
{
  dp[j][k]=maxx(dp[j][k],dp[j-cost[i]][k-fr[i]]+be[i]);
}

4.优化:

题目中有一句话:“询问显然彼此独立”,那是不是意味着我们需要每一组询问都跑一遍\(dp\)呢?显然不是的。

我们可以统计出所有询问中最大的\(c\),记作\(maxc\);统计出最大的\(f\),记作\(maxf\)

我们只需要跑一次\(dp\),得到\(dp[maxc][maxf]\)的结果。试想一下,若\(dp[maxc][maxf]\)跑出来了,那么\(dp[1][1],dp[1][2]...dp[i][j]...dp[maxc][maxf]\)的结果不就都出来了吗~

AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
template <typename T>inline void re(T &x) {
	x=0;
	int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-f;
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
	x*=f;
	return;
}
template <typename T>void wr(T x) {
	if(x<0) putchar('-'),x=-x;
	if(x>9) wr(x/10);
	putchar(x%10^'0');
	return;
}
int maxx(int a,int b)
{
	return a>b?a:b;
}
const int N=505;
int n,q;
int dp[N][N];
int cost[N],fr[N],be[N];
signed main()
{
	re(n);re(q);
	for(int i=1;i<=n;++i)
	{
		re(cost[i]);re(fr[i]);re(be[i]);
	}
	for(int x=1;x<=q;++x)
	{
		memset(dp,0,sizeof(dp));
		int c,f;
		re(c);re(f);
		for(int i=1;i<=n;++i)
			for(int j=c;j>=cost[i];j--)
				for(int k=f;k>=0;k--)
				{
					if(k<=fr[i])
					{
						dp[j][k]=maxx(dp[j-cost[i]][0]+be[i],dp[j][k]);
					}
					else if(dp[j-cost[i]][k-fr[i]])
					{
						dp[j][k]=maxx(dp[j][k],dp[j-cost[i]][k-fr[i]]+be[i]);
					}
				}
		printf("%d\n",dp[c][f]);
	}
	return 0;
}
posted @ 2022-09-29 19:29  Fish4174  阅读(151)  评论(1编辑  收藏  举报