五一模拟赛 JZOJ 4683 Market 线性DP:背包

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/89763633

title

【问题描述】

在这里插入图片描述

【输入】

在这里插入图片描述

【输出】

输出m行,每行一个整数,对于每个计划输出最大可能的价值和

【输入输出样例1】

market.in
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8
5 9
market.out
10
12
在这里插入图片描述

【数据范围】

在这里插入图片描述

analysis

把购物时间排个序,然后做背包?

但是我们发现,预算和金额都非常大,没法背包怎么办呢?

经典的做法是,互换一下,将价值设为状态预算设为背包的值,然后再二分判断就好。

即设 f [ i ] [ j ] f[i][j] 表示前 i i 个店能够购物,购买价值为 j j 的物品。

状态转移方程就很好想了:

if (j>=a[i].v) f[i][j]=min(f[i-1][j],f[i-1][j-a[i].v]+a[i].c);
else f[i][j]=f[i-1][j];

伪装成难题的水题~

这话可不是我说的,是这位大佬说的:BAJim_H,但是这道题还就是这么搞的。。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300,maxv=300;

template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}

struct Orz{int c,v,t;}a[maxn+10];
inline bool cmp(Orz x,Orz y)
{
	return x.t<y.t;
}

int t[maxn+10];
ll f[maxn+10][maxn*maxv+10];//f[i][j]表示前i个店能够购物,购买价值为j的物品
int main()
{
	freopen("market.in","r",stdin);
	freopen("market.out","w",stdout);
	int n,m;read(n);read(m);
	for (int i=1; i<=n; ++i) read(a[i].c),read(a[i].v),read(a[i].t),t[i]=a[i].t;
	sort(t+1,t+n+1);
	sort(a+1,a+n+1,cmp);

	for (int i=1; i<=maxn*maxv; ++i) f[0][i]=99999999999999999ll;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=maxn*maxv; ++j)
			if (j>=a[i].v) f[i][j]=min(f[i-1][j],f[i-1][j-a[i].v]+a[i].c);
			else f[i][j]=f[i-1][j];

	for (int i=1; i<=n; ++i)
		for (int j=maxn*maxv-1; j>=0; --j)
			f[i][j]=min(f[i][j],f[i][j+1]);

	while (m--)
	{
		int T,M;
		read(T);read(M);
		int s=upper_bound(t+1,t+n+1,T)-t-1;
		ll ans=upper_bound(f[s],f[s]+n*maxv+1,M*1ll)-f[s]-1;
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/89763633
今日推荐