五一模拟赛 value 线性DP:背包

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

title

【问题描述】
在这里插入图片描述
【输入】
在这里插入图片描述

【输出】
在这里插入图片描述

【输入输出样例1】

value.in
5
8 2
10 7
5 1
11 8
13 3
value.out
27

【数据范围】

在这里插入图片描述

analysis

这道题一眼看过去,以为排个序做个背包就好,但发现 O ( n w ) O(n*w) 会超时,就尴尬了。。看一下数据,很明显是要 O ( n 2 ) O(n^2) D p Dp
那要怎么 D p Dp 呢。
我们先按 W i Wi 降序的排序,然后贪心的想,我们一定是从后往前取的。 F [ i ] [ j ] F[i][j] 表示前 i i 个物品,从后往前取了 j j 个的最大价值。 那么第 i i 个物品的真正价值就是 V i W i ( j 1 ) Vi-Wi*(j-1) ,即减去对在它后面取的物品(排序在它前面的物品)的影响。
总式为 F [ i ] [ j ] = M a x { F [ i 1 ] [ j ] , F [ i 1 ] [ j 1 ] + v [ i ] w [ i ] ( j 1 ) } F[i][j]=Max\left\{ F[i−1][j] , F[i−1][j−1]+v[i]−w[i]∗(j−1) \right\}

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e3+10;

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 v,w;}a[maxn];
inline bool cmp(Orz x,Orz y)
{
	return x.w>y.w;
}

ll f[maxn][maxn],ans;
int main()
{
	freopen("value.in","r",stdin);
	freopen("value.out","w",stdout);
	int n;read(n);
	for (int i=1; i<=n; ++i) read(a[i].v),read(a[i].w);

	sort(a+1,a+n+1,cmp);
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=n; ++j)
			f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].v-(j-1)*a[i].w);			

	for (int i=1; i<=n; ++i) ans=max(ans,f[n][i]);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/89763722