关于dp,看到一篇很好的博客:到底什么是dp思想(内含大量经典例题,附带详细解析)
题干:
在遥远的东方,有一家糖果专卖店。
这家糖果店将会在每天出售一些糖果,它每天都会生产出m个糖果,第i天的第j个糖果价格为C[i][j]元。
现在的你想要在接下来的n天去糖果店进行选购,你每天可以买多个糖果,也可以选择不买糖果,但是最多买m个。(因为最多只生产m个)买来糖果以后,你可以选择吃掉糖果或者留着之后再吃。糖果不会过期,你需要保证这n天中每天你都能吃到至少一个糖果。
这家店的老板看你经常去光顾这家店,感到非常生气。(因为他不能好好睡觉了)于是他会额外的要求你支付点钱。具体来说,你在某一天购买了 k 个糖果,那么你在这一天需要额外支付 k^2的费用。
那么问题来了,你最少需要多少钱才能达成自己的目的呢?
思路:
- 求花最少的钱,使得 n 天至少每天吃一颗糖
- 可以知道,应该只买 n 颗糖,并且买每天更便宜的糖(每日糖的价格由低到高排序)
- 涉及到最优决策,考虑用 dp 解决。
dp[i][j] 表示:前 i 天买了 j 颗糖 花费的最少钱数。可以由(前 i-1 天 + 第 i 天)推过来。
状态转移方程(前 i-1 天买了 k 颗糖):
dp[i][j] = min( dp[i][j] , dp[i-1][k] + sum[i][j-k] + (j-k)*(j-k) );
-
枚举天数 for(int i=1; i<=n; i++)
-
枚举前 i 天买的糖果数 for(int j=i; j<=min(n, i*m); i++)
2.1 由于前 i 天一定至少买了 i 个糖果,所以 j 从 i 开始;
2.2 j 一定小于等于 n(一共需要买 n 颗) 和 i*m(前 i 天生产的最大量),取最小值 -
枚举前 i-1 天买的糖果数 for(int k=i-1; k<=min(n, (i-1)*m)&&k<=j; k++)
3.1 由于前 i-1 天一定至少买了 i-1 个糖果,所以 k 从 i-1 开始;
3.2 j 一定小于等于 n(一共需要买 n 颗) 和 (i-1)*m(前 i 天生产的最大量),取最小值;且 k 一定小于等于 j 。
- 最后输出 dp[n][n],表示前 n 天买了 n 颗糖花费的最少钱数。
#include <bits/stdc++.h>
using namespace std;
int c[