题目链接:https://www.luogu.com.cn/problem/P1417
分析:
1.此题目为什么不能用普通的01背包呢?因为01背包的要求是不同顺序的选取对结果不会造成影响,而此题不是,此题相同的总选取物品在不同选取顺序下,得到的答案是不同的。(也可以看成,价值在不断的改变,虽然物品没变,但是在不同的时间取,对应的价值不同,实际上就可以看成是不同的物品。所以不能用普通的01背包)。
2.还需要加上贪心的思路:
列一下公式,两个物品哪种取值是最优的呢?,i,j两个物品
i先取然后取j:a[i]−b[i]∗(t+c[i])+a[j]−b[j]∗(t+c[i]+c[j])
j先取然后取i: a[j]−b[j]∗(t+c[j])+a[i]−b[i]∗(t+c[i]+c[j])
当a[i]−b[i]∗(t+c[i])+a[j]−b[j]∗(t+c[i]+c[j]) >= a[j]−b[j]∗(t+c[j])+a[i]−b[i]∗(t+c[i]+c[j])时,i先取更优。
进行化简,消元
--------》 −b[i]∗(t+c[i])−b[j]∗(t+c[i]+c[j]) >= −b[j]∗(t+c[j])−b[i]∗(t+c[i]+c[j])
--------》−b[j]∗c[i]>−b[i]∗c[j]
所以两个物品按照此方式进行排序即可。当−b[j]∗c[i]>−b[i]∗c[j], i放前面,先选择i.
这样就可以使用01背包了。
状态表示:
f[i][j] : 前i个物品,i完成时,到达j分钟 获得的最大价值
代码实现:
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int N = 60 , M = 100010;
long long f[2][M];
int t,n;
struct Node
{
long long a,b,c;
}tr[N];
bool cmp(struct Node t1 , struct Node t2)
{
return -t2.b * t1.c > -t1.b * t2.c;
}
int main()
{
scanf("%d %d",&t,&n);
for(int i = 1 ; i <= n ;i++)
{
scanf("%lld",&tr[i].a);
}
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&tr[i].b);
}
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&tr[i].c);
}
sort(tr + 1 , tr + 1 + n , cmp);
long long ans = -0x3f3f3f3f;
for(int i = 1 ; i <= n ; i++)
{
for(int j = t ; j >= 0 ; j--)
{
f[i % 2][j] = f[ (i - 1) % 2][j];
if(tr[i].c <= j)
{
f[i % 2][j] = max(f[i % 2][j],f[ (i - 1) % 2][j - tr[i].c ] + tr[i].a - j * tr[i].b);
}
}
}
for(int i = 0 ; i <= t ; i++)
{
ans = max(ans,f[n % 2][i]);
}
printf("%lld\n",ans);
return 0;
}
这篇博客分析了一个不能直接应用普通01背包算法的题目,原因是选取顺序对结果有影响。博主提出了一种贪心策略,通过比较物品在不同选取顺序下的价值变化来排序物品,并给出了状态转移方程和代码实现。最终,通过贪心排序后的01背包解决了问题。
333

被折叠的 条评论
为什么被折叠?



