每日一题 购物 dp

题目:https://ac.nowcoder.com/acm/problem/14526
题目描述
在遥远的东方,有一家糖果专卖店。

这家糖果店将会在每天出售一些糖果,它每天都会生产出m个糖果,第i天的第j个糖果价格为C[i][j]元。

现在的你想要在接下来的n天去糖果店进行选购,你每天可以买多个糖果,也可以选择不买糖果,但是最多买m个。(因为最多只生产m个)买来糖果以后,你可以选择吃掉糖果或者留着之后再吃。糖果不会过期,你需要保证这n天中每天你都能吃到至少一个糖果。

这家店的老板看你经常去光顾这家店,感到非常生气。(因为他不能好好睡觉了)于是他会额外的要求你支付点钱。具体来说,你在某一天购买了 k 个糖果,那么你在这一天需要额外支付 k2 的费用。

那么问题来了,你最少需要多少钱才能达成自己的目的呢?

题解:用动态规划,其中最优值问题,最小值那么需要买的糖果是n个。用dp,dp[i][j]表示第i天买了j个糖果的最小费用,那么它是从第i-1天买k个糖果的最小费用转移过来的,既dp[i-1][k],状态转移方程是dp[i][j] = min(dp[i][j], dp[i - 1][k] + cal(j-k, i) + (j - k) (j - k))
其中当天的糖果数j始终大于等于天数i,小于总数n和每天都取全部m
i的较小值。
前一天的果数k同理。
答案为dp[n][n]

对于答案我们显然是在第nnn天刚好购买了nnn个糖果,这样是最优的,对于每一天购买糖果,我们一定是优先选择花费更小的,这样才能保证最优值.

输入描述:
第一行两个正整数n和m,分别表示天数以及糖果店每天生产的糖果数量。
接下来n行(第2行到第n+1行),每行m个正整数,第x+1行的第y个正整数表示第x天的第y个糖果的费用。

输出描述:
输出只有一个正整数,表示你需要支付的最小费用。
代码:

#include <bits/stdc++.h>
#include <algorithm>
#include<iostream>
#include <stdio.h>
#define INF 0x3f3f3f3f
//const int maxn=;
using namespace std;
typedef long long ll;
int c[305][305];
int dp[305][305];
int cal(int k, int n) {
    
    
	int s = 0;
	for (int i = 1; i <= k; i++) {
    
    
		s += c[n][i];
	}
	return s;
}
int main()
{
    
    
	//freopen("D:\\input.txt", "r", stdin);
	//freopen("D:\\output.txt", "w", stdout);
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
    
    
		for (int j = 1; j <= m; j++) {
    
    
			cin >> c[i][j];
		}
		sort(c[i] + 1, c[i] + 1 + m);
	}
    memset(dp,0X3f,sizeof(dp));
	dp[0][0]=0;
	for (int i = 1; i <= n; i++) {
    
    
		for (int j = i; j <= min(n, m*i); j++) {
    
    
			for (int k = i-1; k <=min(n,(i-1)*m)&&k<=j; k++) {
    
    
				dp[i][j] = min(dp[i][j], dp[i - 1][k] + cal(j-k, i) + (j - k) *(j - k));
			}
		}
	}
	cout << dp[n][n] << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/u011612364/article/details/108435041