28.考试

Description

小学期马上就要结束了,为了检验大家的学习成果,老师进行了一次考试。然而小徐前两周半都忙于练习篮球,几乎没有学习,因此考试时很可能做不完所有题目。

但小徐仍然想要拿到尽可能高的分数,因此在做题时需要合理做出取舍。已知考试时间为 分钟,小徐希望在不超时的情况下,考出最高的分数。

设做出第 j j j道试题用时为, 该试题的”性价比”为 w [ i ] w[i] w[i], ( t [ j ] ∗ w [ j ] t[j]*w[j] t[j]w[j] 为做出该题的得分 )

若选择了 k k k题进行作答,则所求的分数之和为 t [ j 1 ] × w [ j 1 ] + t [ j 2 ] × w [ j 2 ] + . . . + t [ j k ] × w [ j k ] t[j_{1}] \times w[j_{1}] \quad + \quad t[j_{2}] \times w[j_{2}] \quad + \quad ... \quad + \quad t[j_{k}] \times w[j_{k}] t[j1]×w[j1]+t[j2]×w[j2]+...+t[jk]×w[jk]

请你帮小徐算出他最高能得多少分。

Input

第一行,为2个正整数,用一个空格隔开: n , m n, m n,m,其中 n n n表示总分钟数, m m m 为考试的题目数量
从第2行到第 m + 1 m+1 m+1行,第 j j j行给出了编号为 j − 1 j-1 j1的题目的基本数据,每行有2个非负整数 t , w t, w t,w .其中 t t t表示小徐做出该题目的所用时间, w w w表示该题目的”性价比”。

Output

一个整数,表示小徐最高能得多少分。

Note

数据保证 n < 30000 , m < 25 , v ≤ 10000 n<30000, m<25, v \leq 10000 n<30000,m<25,v10000 w w w 1 − 5 1-5 15

测试输入期待的输出
测试用例1
  1. 1000 5
  2. 800 2
  3. 400 5
  4. 300 5
  5. 400 3
  6. 200 2
  1. 3900
测试用例2
  1. 22415 2
  2. 2824 3
  3. 2485 3
  1. 15927

思路

和0-1背包问题完全一致,没有任何特殊的地方。
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示考试时长为j时前i道题目可以取得的最高分。
如果 j > = t [ i ] j>=t[i] j>=t[i] ,表示第 i i i 题有时间完成,我们有两种选择,做或不做择其优。

  • 不做, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
  • 做,留出 t [ i ] t[i] t[i] 的时间给第 i i i 题,则前 i − 1 i-1 i1 道题的最佳方案是 d p [ i − 1 ] [ j − t [ i ] ] + w [ i ] dp[i-1][j-t[i]]+w[i] dp[i1][jt[i]]+w[i]

两者取其大
如果时间不足,只能是 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]。最后输出dp[m][n]
由于我们不需要输出具体方案,可以尝试使用一维dp[j]来记录。此时需注意考试时间需要从大到小遍历,防止覆盖有效数据。

代码

#include<stdio.h>
#define N 10005
int t[N]={0},w[N]={0},fen[N]={0},dp[30000]={0};

int max(int a,int b)
{
	if(a>=b)	return a;
	else	return b;
}
main()
{
	int n,m,i,j;
	// n为背包容量,m为物品个数,t为物品大小,fen为物品价值。
	scanf("%d %d",&n,&m);
	for(i=1;i<=m;i++){
		scanf("%d %d",&t[i],&w[i]);
		fen[i]=t[i]*w[i];
	}
	for(i=1;i<=m;i++){
		for(j=n;j>0;j--){
			if(j<t[i])	dp[j]=dp[j];
			else	dp[j]=max(dp[j],dp[j-t[i]]+fen[i]);
		}
	}
	printf("%d\n",dp[n]);
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北辰2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值