题目
试题编号 | 202209-2 |
---|---|
试题名称 | 何以包邮 |
时间限制 | 1s |
内存限制 | 512MB |
问题描述 | |
输入输出 | |
样例1 | |
样例2 | |
样例3 |
题目分析
动态规划。就是一个0/1背包问题。
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前i本书,在超过总钱数为j情况下的最小钱数目。
若
j
<
p
r
i
c
e
i
j<price_i
j<pricei,则:
d
p
[
i
]
[
j
]
=
m
i
n
(
p
r
i
c
e
i
,
d
p
[
i
−
1
]
[
j
]
)
dp[i][j]=min(price_i,dp[i-1][j])
dp[i][j]=min(pricei,dp[i−1][j])
若
j
>
=
p
r
i
c
e
i
j>=price_i
j>=pricei,则:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
−
p
r
i
c
e
i
]
+
p
r
i
c
e
i
,
d
p
[
i
−
1
]
[
j
]
)
dp[i][j]=min(dp[i-1][j-price_i]+price_i,dp[i-1][j])
dp[i][j]=min(dp[i−1][j−pricei]+pricei,dp[i−1][j])
可以看到dp的更新只基于前一行且有从后往前更新的顺序,那么可以用一维滚动数组dp[300000]直接计算。
AC代码(100分)
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
#define min(a,b) ((a)<(b)?(a):(b))
int n,x;
int a;
int dp[300000];
int ans=0;
int main(){
scanf("%d%d",&n,&x);
memset(dp,0x3f,sizeof(dp));
rep(i,0,n){
scanf("%d",&a);
ans+=a;
for(int j=ans;j>0;j--){
if(j>a)dp[j]=min(dp[j],dp[j-a]+a);
else dp[j]=min(dp[j],a);
}
}
printf("%d",dp[x]);
return 0;
}
/*
4 10
2
9
6
6
*/