hznuoj题目
【C系列综合1】游戏达人I
Description
ACM队的ydw是个游戏的狂热爱好者,他喜好玩各种各样的单机游戏,以可以得到各种不同的结局通关为乐,但是由于时间有限(他还要出题TAT),于是他只能选择自己喜欢的几个结局来通关,由于ydw是游戏达人,因此他可以自己搞定所有的剧情而不去查攻略,但是由于自力更生,完成每个结局的时间是不同的,而他对每一个结局的喜好度也是不同的,即通关每个结局他获得的愉悦度是不同的。他希望在自己有限的时间内可以通关某些结局来使得自己的愉悦度最大。
Input
有多组测试数据,
第1行为N(0<N<=100)和T(0<T<=2000),表示ydw有N个游戏可以玩,玩游戏的总的时间为T。
接下来3*N行,每行第一个数字n(1<=n<=10)表示这个游戏有几种结局,接下来的一行n个数字表示通关某个结局ydw可以获得的愉悦度,再接下来一行的n个数字表示ydw通关某个结局需要的时间。
测试数据以0 0结尾。(数据保证愉悦度和时间均大于0,小于等于1000)
Output
ydw可以获得的最大愉悦度。
Samples
解题方法学习自【动态规划】01背包问题(通俗易懂,超基础讲解)
题目分析
总体思路
把大问题拆分成小问题
解决方案
简化问题:有m个结局,每个结局玩完可以获得h点愉悦度,并消耗t点时间,总共有T的时间,问最多能获得多少愉悦度。
定义happy[i]为每个结局可获得的愉悦度
time[i]为每个结局要消耗的时间
定义H(i,j):当前所剩时间j,前 i 个结局所能带来的最大愉悦度
当第i个结局所需时间大于剩下可用的时间
H(i,j) = H(i-1,j) //即第i个结局玩不了了
当第i个结局所需时间小于等于剩下的可用时间
H(i,j) = H(i-1,j) //不玩第i个结局
或 H(i,j) = H(i - 1,j - t[i]) + h[i] //玩第i个结局(两个方案使用愉悦度多的)
可以借助图表来进行分析
(示例数据为 h(2,3,4)t(1,4,3))T为7
如,i=1,j=1,t(1)=1,h(1)=2,有j=t(1),故H(1,1)=max{ H(1-1,1),H(1-1,2-t(1))+h(1) }=2 ;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
2 | 0 | 2 | 2 | 2 | 3 | 5 | 5 | 5 |
3 | 0 | 2 | 2 | 4 | 6 | 6 | 6 | 7 |
原理大致了解之后,开始解题。
解题结构
1.定义一个结构体 来储存每个游戏的每个结局所需的愉悦度,如下:
struct game{
int happy[100];
int time[100];
int type;
}g[110];
2.定义另外一个结构体来储存每个结局的信息,如下:
struct res{ //用来接收所有类型结局的数据
int happy;
int time;
}r[11000];
3.定义图表
int charm[1010][2010]={{0}};//定义动态规划表
4.定义一个max函数
int Max(int x,int y){ //定义一个返回较大值的函数
return x>y?x:y;
}
5.输入题目要求的数据
int N,T;
int n;
int H=0; //记录总共可以获得多少愉悦度
while(scanf("%d %d",&N,&T),(N||T)){ //输入 N 个游戏,总共 T 时间
for(int i=0;i<N;i++){ //输入每个游戏有n个结局
scanf("%d",&g[i].type);
for(int j=0;j<g[i].type;j++) //输入n个结局的愉悦度
scanf("%d",&g[i].happy[j]);
for(int j=0;j<g[i].type;j++) //输入n个结局的所需时间
scanf("%d",&g[i].time[j]);
}
}
6.把输入的值复制一份到res结构体中,方便对每个游戏的所有结局进行规划
int m=1;
r[0].happy=0;
r[0].time=0;
for(int i=0;i<N;i++){
//把每个结局的数据复制到res结构体中
for(int j=0;j<g[i].type;j++){
r[m].happy=g[i].happy[j];
r[m].time=g[i].time[j];
m++;
}
}
7.开始做动态分配操作
//m为所有结局的总数
/*动态规划时间分配 从r[1].happy~r[m].happy是每个结局可获得的愉悦度
r[1].time ~r[m]. time是每个结局所需的时间 */
//动态规划表大小应为 (m+1)*(T+1)
for (int i=1;i<=m;i++) {
for (int j=1;j<=T;j++) {
if (j<r[i].time)
charm[i][j] = charm[i-1][j];
else
charm[i][j] = Max(charm[i-1][j], charm[i-1][j-r[i].time] + r[i].happy);
}
}
H=charm[m][T];
8.最后打印结果
printf("%d\n",H);
全部代码:
#include<stdio.h>
int charm[1010][2010]={{0}};//定义动态规划表
int Max(int x,int y){ //定义一个返回较大值的函数
return x>y?x:y;
}
struct game{
int happy[100];
int time[100];
int type;
}g[110];
struct res{ //用来接收所有类型结局的数据
int happy;
int time;
}r[11000];
int main()
{
int N,T;
int n;
int H=0; //记录总共可以获得多少愉悦度
while(scanf("%d %d",&N,&T),(N||T)){ //输入 N 个游戏,总共 T 时间
for(int i=0;i<N;i++){ //输入每个游戏有n个结局
scanf("%d",&g[i].type);
for(int j=0;j<g[i].type;j++) //输入n个结局的愉悦度
scanf("%d",&g[i].happy[j]);
for(int j=0;j<g[i].type;j++) //输入n个结局的所需时间
scanf("%d",&g[i].time[j]);
}
int m=1;
r[0].happy=0;
r[0].time=0;
for(int i=0;i<N;i++){
//把每个结局的数据复制到res结构体中
for(int j=0;j<g[i].type;j++){
r[m].happy=g[i].happy[j];
r[m].time=g[i].time[j];
m++;
}
}
m--;
/*动态规划时间分配 从r[0].happy~r[m].happy是每个结局可获得的愉悦度
r[0].time ~r[m]. time是每个结局所需的时间 */
//动态规划表大小应为 (m+1)*(T+1)
for (int i=1;i<=m;i++) {
for (int j=1;j<=T;j++) {
if (j<r[i].time)
charm[i][j] = charm[i-1][j];
else
charm[i][j] = Max(charm[i-1][j], charm[i-1][j-r[i].time] + r[i].happy);
}
}
H=charm[m][T];
printf("%d\n",H);
}
return 0;
}