版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89763965
题目描述
题解
这道题可能就是比较经典的费用提前的题吧,但是我考场上莫有想到可能是忘记了吧。
对于费用计算,我们可以这么理解:对于每一件物品,当它使用过以后其他物品的价值都会下降。因此我们在当前状态的时候就减去一个下降的值,这样其他的每一件物品在通过这个状态转移的时候就会下降了。
理解了这么一个思想,我们就有一个问题,就是减去的值为多少呢?我们发现,若这个物品被选的顺序是倒数第一,那么就不选;如果是倒数第二,那就减去一倍的 ;倒数第三时,有两个数要减去 ,所以在当前状态转移 倍的 。一次类推,如果是倒数第 ,就减去 倍的 即可。
除此之外,因为选的顺序是没有要求的,更小的先选会减的更小,所以我们从小到大选取。由于在状态转移的时候需要倒序枚举,所以我们从大到小排序即可。
我们设 表示选到第 个物品,选了 件的最大价值。有状态转移方程:
代码如下:
#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;
}