1. 程式人生 > 實用技巧 >紀中週末訓練 2020.09.19【NOIP提高B組】模擬 T2:【Usaco2009 gold】電視遊戲問題

紀中週末訓練 2020.09.19【NOIP提高B組】模擬 T2:【Usaco2009 gold】電視遊戲問題

【Usaco2009 gold】電視遊戲問題

Description

農夫約翰的奶牛們遊戲成癮!本來FJ是想要按照陶叫獸的做法拿她們去電擊戒癮的,可是後來他發現奶牛們玩遊戲之後比原先產更多的奶。很明顯,這是因為滿足的牛會產更多的奶。
但是,奶牛們在哪個才是最好的遊戲平臺這個問題上產生了巨大的分歧。一隻奶牛想要買一臺Xbox 360來跑《光暈3》;另外一隻奶牛想要一臺任天堂Wii來跑《任天堂明星大亂鬥X》;第三隻奶牛想要在PlayStation 3上面玩《潛龍諜影4》,順便還能看某些高畫質的日本電影。
FJ想要在給定的預算內購入一些遊戲平臺和一些遊戲,使他的奶牛們生產最多的奶牛以養育最多的孩子。
FJ研究了N(1 <= N <= 50)種遊戲平臺,每一種遊戲平臺的價格是P_i(1 <= P_i <= 1000),並且每一種遊戲平臺有G_i(1 <= G_i <= 10)個只能在這種平臺上執行的遊戲。很明顯,奶牛必須先買進一種遊戲平臺,才能買進在這種遊戲平臺上執行的遊戲。每一個遊戲有一個遊戲的價格GP_j(1 <= GP_j 價格 <= 100)並且有一個產出值PV_j(1 <= PV_j<= 1000000),表示一隻牛在玩這個遊戲之後會產出多少牛奶。
最後,農夫約翰的預算為V(1 <= V <= 100000),即他最多可以花費的金錢。請幫助他確定應該買什麼遊戲平臺和遊戲,使得他能夠獲得的產出值的和最大。
考慮下面的資料,有N種遊戲平臺,並且有V=$800預算。第一種遊戲平臺花費$300並且有兩個遊戲,價格分別為$30和$25,它們的產出值如下所示:
遊戲 # 花費 產出值
1 $30 50
2 $25 80
第二種平臺價格為$600,並且只有一種遊戲:

遊戲 # 花費 產出值
1 $50 130
第三種平臺價格為$400,並且有三種遊戲:

遊戲 # 花費 產出值
1 $40 70
2 $30 40
3 $35 60
農夫約翰應該買第1和第3種平臺,並且買平臺1的遊戲2,還有平臺3的遊戲1和遊戲3。使得
最後他最後的產出值最大,為210:

產出值
預算: $800
平臺 1 -$300
遊戲 2 -$25 80
平臺 3 -$400
遊戲 1 -$40 70
遊戲 3 -$35 60

總計: 0 (>= 0) 210

Input

第1行: 兩個由空格隔開的整數: N和V
第2到第N+1行: 第i+1行表示第i種遊戲平臺的價格和可以在這種遊戲平臺上面執行的遊戲。包含: P_i, G_i還有G_i對由空格隔開的整數GP_j, PV_j

Output

第1行: 農夫約翰在預算內可以得到的最大的產出值。

Sample Input

3 800
300 2 30 50 25 80
600 1 50 130
400 3 40 70 30 40 35 60

反思&題解

比賽思路&正解思路: 很明顯這題的模型是個揹包,只是多了一個“必須買了平臺才能玩遊戲的規則”,其實思路也差不多
\(f1[i]\)表示花了i的價格獲得的最大產出量,\(f2[i]\)表示在某個平臺裡花了i塊錢獲得的最大產出量,之後我們考慮怎麼將這兩個狀態聯絡在一起,很顯然對於某個平臺價格為S時,\(f2[i]=f1[i-S]\)
之後在每個平臺裡面的遊戲做一個01揹包,每個\(f1\)再取\(f1\)

\(f2\)中較優的一個就行了
反思: 感覺最近DP的感覺不錯

CODE

#include<bits/stdc++.h>
using namespace std;
int n,v,f1[100005],f2[100005];
int main()
{
	freopen("vidgame.in","r",stdin);
	freopen("vidgame.out","w",stdout);
	scanf("%d%d",&n,&v);
	int i;
	for (i=1;i<=n;i++)
	{
		int p,g;
		scanf("%d%d",&p,&g);
		int j;
		memset(f2,0,sizeof(0));
		for (j=p;j<=v;j++)
			f2[j]=f1[j-p];
		for (j=1;j<=g;j++)
		{
			int gp,pv;
			scanf("%d%d",&gp,&pv);	
			int k;
			for (k=v;k>=gp+p;k--)
				f2[k]=max(f2[k],f2[k-gp]+pv);
		}
		for (j=1;j<=v;j++)
			f1[j]=max(f1[j],f2[j]);
	}
	printf("%d\n",f1[v]);
	return 0;
}