您的位置:首页 > 其它

牛客练习赛7:B-购物 (dp)

2017-12-03 09:28 344 查看
题目链接:https://www.nowcoder.com/acm/contest/38/B

题目描述:

给出N,M,有N天,每天店里都生产M颗糖果,这N天要去商店买

糖果,但是有一个条件,如果某天买的糖果数是K个,则需要额外

花费K*K的钱,而且要保证每天都有糖果吃。问购物的最小花费。

解题思路:

贪心+dp.

从题目中提取信息。每天都要买糖果吃,则前i天买的糖果数量

至少是i,而且最少买N颗糖果就可以满足条件,为了使花钱最少,

某天买k件的话,希望是当天糖果的前k小。所以对于每天给出的

M个糖果,按价格从小到大排序。这样就能计算出某天买K件的最

小花费。然后设立数组,dp[i][j]代表的含义是前i天至少买j件的最

小花费。由于前i天至少买i个,所以对于前i天,j的范围是从i~N,

然后我们可以枚举第i天买多少件,然后其状态可以由前i-1天买

糖果数得来。由于第1天必须买,而剩余N天可以有买的情况,

和不买的情况,所以可以把第一天抽出来考虑。

比赛的时候我没有把第一天单独抽出来,导致思路极度混乱,

我来我就单独处理第一天,其他的都按他们的条件处理,然后

就直接交过了,真的应该早点把他抽出来。

AC代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 305;
int dp[maxn][maxn]; ///dp[i][j]前i天买j件的最少花费
int temp[maxn]; ///临时存放第i天糖果价格的数组
int price[maxn][maxn]; ///price[i][j]第i天买j件的最小花费
///需要N天,则需要N个糖果
int main() {
int N,M;
while(~scanf("%d%d",&N,&M)) {
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
scanf("%d",&temp[j]);
}
sort(temp+1,temp+1+M); ///对每组价格排序
price[i][0] = 0;
for(int j = 1; j <= M; j++) {
price[i][j] = price[i][j-1]+temp[j]-(j-1)*(j-1)+j*j;
}
}
int Max = max(M,N);
for(int i = 0; i <= N; i++) {
for(int j = 0; j <= Max; j++) {
if(i == 0)
dp[i][j] = 0;
else
dp[i][j] = inf;
}
}
/**由于每天必须有糖果吃,因此第1天必须买,
而剩余几天可能买,可能不买,第一天与其他
天情况考虑不一致,单独抽出来求**/
for(int j = 1; j <= M; j++) {
dp[1][j] = price[1][j];
}
for(int i = 2; i <= N; i++) {
///前i天买k个糖果,由于前i天至少买i个糖果,所以k>=i
for(int k = N; k >= i; k--) {
///枚举第i天买了多少糖果,前i-1天至少买i-1个糖,所以k-j>=i-1
for(int j = 0; j <= M; j++) {
if(k-j >= i-1) {
dp[i][k] = min(dp[i][k],dp[i-1][k-j]+price[i][j]);
}
}
}
}
printf("%d\n",dp

);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: