櫻花 混合揹包

題目描述
愛與愁大神後院裏種了n棵櫻花樹,每棵都有美學值Ci。愛與愁大神在每天上學前都會來賞花。愛與愁大神可是生物學霸,他懂得如何欣賞櫻花:一種櫻花樹看一遍過,一種櫻花樹最多看Ai遍,一種櫻花樹可以看無數遍。但是看每棵櫻花樹都有一定的時間Ti。愛與愁大神離去上學的時間只剩下一小會兒了。求解看哪幾棵櫻花樹能使美學值最高且愛與愁大神能準時(或提早)去上學。

輸入格式
共n+1行:

第1行:三個數:現在時間Ts(幾點:幾分),去上學的時間Te(幾點:幾分),愛與愁大神院子裏有幾棵櫻花樹n。

第2行~第n+1行:每行三個數:看完第i棵樹的耗費時間Ti,第i棵樹的美學值Ci,看第i棵樹的次數Pi(Pi=0表示無數次,Pi是其他數字表示最多可看的次數Pi)。

輸出格式
只有一個整數,表示最大美學值。

輸入輸出樣例
輸入 #1
6:50 7:00 3
2 1 0
3 3 1
4 5 4
輸出
11

很明顯就是混合揹包問題,01揹包和完全揹包可以直接套模板,多重揹包可以二進制拆分轉化爲01揹包,剛開始拆分又拆錯了,每個多重揹包有最大次數,拆分的物品不僅是小於他的二進制數還得滿足這些數的和必須等於他的次數,因爲物品的不能超過他的最大次數

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;範圍一定得開大點
ll n,m,x,w[N],t[N],dp[N],idx;
bool st[N];
int main()
{
	int v,b,c,d,e;
	scanf("%d:%d %d:%d %d",&b,&c,&d,&e,&n);
	v=d*60+e-b*60-c;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d%d",&b,&c,&d);
		if(!d) 
		{
			t[idx]=b;
			w[idx]=c;
			st[idx++]=1;//標記完全揹包
		}
		else 
		{
			int cnt=1;
			while(d>=cnt)//拆分,01揹包的次數是1也不會拆錯
			{
				t[idx]=1ll*b*(cnt);
				w[idx++]=1ll*c*(cnt);
				d-=cnt;
				cnt= cnt<<1;
			}
			if(d!=0) 
			{
				t[idx]=1ll*b*(d);
				w[idx++]=1ll*c*(d);
			}
		}
	}
	n=idx;
	for(int i=0;i<n;i++)
	{
		if(st[i])
			for(int j=t[i];j<=v;j++)
				dp[j]=max(dp[j],dp[j-t[i]]+w[i]);
		else 
			for(int j=v;j>=t[i];j--)
				dp[j]=max(dp[j],dp[j-t[i]]+w[i]);
	}
	cout<<dp[v];
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章