『动态规划·贪心』最优价值

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89763965

题目描述

在这里插入图片描述

题解

这道题可能就是比较经典的费用提前的题吧,但是我考场上莫有想到可能是忘记了吧。

对于费用计算,我们可以这么理解:对于每一件物品,当它使用过以后其他物品的价值都会下降。因此我们在当前状态的时候就减去一个下降的值,这样其他的每一件物品在通过这个状态转移的时候就会下降了。

理解了这么一个思想,我们就有一个问题,就是减去的值为多少呢?我们发现,若这个物品被选的顺序是倒数第一,那么就不选;如果是倒数第二,那就减去一倍的 w w ;倒数第三时,有两个数要减去 w w ,所以在当前状态转移 2 2 倍的 w w 。一次类推,如果是倒数第 n n ,就减去 ( n 1 ) (n-1) 倍的 w w 即可。

除此之外,因为选的顺序是没有要求的,更小的先选会减的更小,所以我们从小到大选取。由于在状态转移的时候需要倒序枚举,所以我们从大到小排序即可。

我们设 f [ i ] [ j ] f[i][j] 表示选到第 i i 个物品,选了 j j 件的最大价值。有状态转移方程: f [ i ] [ j ] = m a x ( f [ i 1 ] [ j ] , f [ i 1 ] [ j 1 ] ( j 1 ) w i + v i ) f[i][j]=max(f[i-1][j],f[i-1][j-1]-(j-1)*w_i+v_i)

代码如下:

#include <bits/stdc++.h>

using namespace std;

int n;
struct node
{
	int v,w;
};
int ans = -1e9;
int f[6000][6000];
node a[1000000];

inline bool cmp(node p1,node p2)
{
	return p1.w>p2.w;
}

int main(void)
{
	freopen("value.in","r",stdin);
	freopen("value.out","w",stdout);
	cin>>n;
	for (int i=1;i<=n;++i) 
		scanf("%d %d",&a[i].v,&a[i].w);
	sort(a+1,a+n+1,cmp);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=i;++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]);
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/89763965