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
j−1的题目的基本数据,每行有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,v≤10000, w w w 为 1 − 5 1-5 1−5
测试输入 | 期待的输出 | |
---|---|---|
测试用例1 |
|
|
测试用例2 |
|
|
思路
和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[i−1][j];
- 做,留出 t [ i ] t[i] t[i] 的时间给第 i i i 题,则前 i − 1 i-1 i−1 道题的最佳方案是 d p [ i − 1 ] [ j − t [ i ] ] + w [ i ] dp[i-1][j-t[i]]+w[i] dp[i−1][j−t[i]]+w[i]
两者取其大
如果时间不足,只能是
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
dp[i][j]=dp[i-1][j]
dp[i][j]=dp[i−1][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]);
}