思维难度较大 贪心优化背包 [USACO22DEC] Bribing Friends G

[USACO22DEC] Bribing Friends G

显然背包可做, 只不过时间复杂度预计 O ( n 4 ) O(n^4) O(n4), 严重超时. 但是考场上写出暴力背包已经可以拿 75 分了, Oier 狂喜. 但可惜, 我打 Acm .

于是我们不妨想想怎么优化.

如果我们已经确定了选哪几位朋友, 那么把冰淇凌给需求冰淇凌最少的那头牛就行. 于是我们不妨按照 x x x 从大到小排序. 首先设 f ( i , j ) f(i,j) f(i,j) 表示前 i i i 项当我们用了 j j j 元后的好感度总和, 显然有

f ( i , j ) = { f ( i − 1 , j ) j < c min ⁡ { f ( i − 1 , j ) , f ( i − 1 , j − c ) + p } c ≤ j ≤ B f(i,j)=\begin{cases}f(i-1,j)\ \ \ \ \ j<c\\ \min\left\{f(i-1,j),f(i-1,j-c)+p\right\}\ \ \ \ c\le j\le B\end{cases} f(i,j)={f(i−1,j) j<cmin{f(i−1,j),f(i−1,j−c)+p} c≤j≤B

cpp 复制代码
for(int i=1;i<=n;P(i)){
	for(int j=0;j<cow[i].c;P(j))f[i][j]=f[i-1][j];
	for(int j=cow[i].c;j<=A;P(j))f[i][j]=std::max(f[i-1][j],f[i-1][j-cow[i].c]+cow[i].p);
}

我们不妨再设 f 1 ( i , j ) f_1(i,j) f1(i,j) 为前 i i i 项我们用 j j j 个甜筒后可获取的最大受欢迎度. 显然我们最多可以减少 r e d u c e = min ⁡ { c , j / x } reduce=\min\{c,j/x\} reduce=min{c,j/x} 元, 同样我们剩下 r e s t = j − r e d u c e ∗ x rest=j-reduce*x rest=j−reduce∗x 个冰淇淋. 显然当我们减少的钱够贿赂一头牛的钱后显然我们不需要给这头牛任何钱了, 我们可以拿剩余的冰淇淋去给其它奶牛:

f 1 ( i , j ) = max ⁡ { f 1 ( i − 1 , j ) , f 1 ( i − 1 , r e s t ) + p } f_1(i,j)=\max\left\{f_1(i-1,j),f_1(i-1,rest)+p\right\} f1(i,j)=max{f1(i−1,j),f1(i−1,rest)+p}

否则说明我们不能完全通过冰淇淋收买这头奶牛, 还是要给钱, 并且由于我们的奶牛 x x x 是降序, 这也说明之前的牛并不能被收买, 我们预处理的 f f f 就在这里派上用场了:

f 1 ( i , j ) = max ⁡ { f 1 ( i − 1 , j ) , f ( i − 1 , A − ( c − r e d u c e ) ) + p } f_1(i,j)=\max\left\{f_1(i-1,j),f\left(i-1,A-(c-reduce)\right)+p\right\} f1(i,j)=max{f1(i−1,j),f(i−1,A−(c−reduce))+p}

cpp 复制代码
for(int i=1,reduce,rest;i<=n;P(i)){
	for(int j=0;j<=B;P(j)){
		reduce=std::min(cow[i].c,j/cow[i].x);
		rest=j-reduce*cow[i].x;
		if(reduce^cow[i].c)f1[i][j]=std::max(f1[i-1][j],f[i-1][A-(cow[i].c-reduce)]+cow[i].p);
		else f1[i][j]=std::max(f1[i-1][j],f1[i-1][rest]+cow[i].p);
		ans=std::max(ans,f1[i][j]);
	}
}

总代码:

cpp 复制代码
#include<algorithm>
#include<iostream>
#define P(A) A=-~A
typedef long long LL;
#define NUMBER1 2000
int n,A,B,f[NUMBER1+5][NUMBER1+5],f1[NUMBER1+5][NUMBER1+5],ans(0);
struct COW{
	int p,c,x;
	bool operator<(const COW &A)const{return x>A.x;}
}cow[NUMBER1+5];
signed main(){
	std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
	std::cout.tie(nullptr);
	std::cin>>n>>A>>B;
	for(int i=1;i<=n;P(i))std::cin>>cow[i].p>>cow[i].c>>cow[i].x;
	std::sort(cow+1,cow+1+n);
	for(int i=1,reduce,rest;i<=n;P(i)){
		for(int j=0;j<cow[i].c;P(j))f[i][j]=f[i-1][j];
		for(int j=cow[i].c;j<=A;P(j))f[i][j]=std::max(f[i-1][j],f[i-1][j-cow[i].c]+cow[i].p);
		for(int j=0;j<=B;P(j)){
			reduce=std::min(cow[i].c,j/cow[i].x);
			rest=j-reduce*cow[i].x;
			if(reduce^cow[i].c)f1[i][j]=std::max(f1[i-1][j],f[i-1][A-(cow[i].c-reduce)]+cow[i].p);
			else f1[i][j]=std::max(f1[i-1][j],f1[i-1][rest]+cow[i].p);
			ans=std::max(ans,f1[i][j]);
		}
	}
	std::cout<<ans;
	return 0;
}
相关推荐
多米Domi01114 小时前
0x3f第33天复习 (16;45-18:00)
数据结构·python·算法·leetcode·链表
罗湖老棍子15 小时前
【例4-11】最短网络(agrinet)(信息学奥赛一本通- P1350)
算法·图论·kruskal·prim
方圆工作室15 小时前
【C语言图形学】用*号绘制完美圆的三种算法详解与实现【AI】
c语言·开发语言·算法
曹仙逸15 小时前
数据结构day04
数据结构
Lips61115 小时前
2026.1.16力扣刷题
数据结构·算法·leetcode
曹仙逸16 小时前
数据结构day05
数据结构
睡一觉就好了。16 小时前
树的基本结构
数据结构
kylezhao201916 小时前
C# 文件的输入与输出(I/O)详解
java·算法·c#
CodeByV16 小时前
【算法题】堆
算法
kaikaile199517 小时前
A星算法避开障碍物寻找最优路径(MATLAB实现)
数据结构·算法·matlab