标签:
第一次尝试写动态规划(Dynamic Planning)=
问题如下:
-------------------------------------------------------------------------------------------------------------------------
最小代价子母树
设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的和称为总代价,给出一种归并算法,使总代价为最小.
输入、输出数据格式与“石子合并”相同。
输入样例:
4
12 5 16 4
-------------------------------------------------------------------------------------------------------------------------
为了说明算法的过程,我们先分析一些简单的情况:
(1)n=2:
方法e总代价:20+27+40=87
当n=4时,共有5种归并的方法,这5种方法可以分为3类:
1)包括a和b基本方法是先归并前面的3堆,在归并最后一堆,由于归并最后一堆的方法是相同的,所以在归并前3堆时不同的方法将产生不同的结果。a的总代价为54,b的总代价为55,所以第1类方法中a比b优;
2)仅有1种方法,c,分别归并2堆的代价分别为20,20,相加为40,共80;
3)包括d和e,基本方法是先归并后面3堆,再归并第1堆,由于归并第1堆的方法是相同的,所以在归并后3堆时不同的方法将产生不同的结果,由上面的分析可知e比d优;
由此我们可以发现,将每一层的最优解找出来,就可以用组合的方法列举出每两个解得到的解,因为每一个结点都是最优解,所以各个最优解组合出来的解也必定为最优解之一,再从中找出最小的一个就是该根结点所对应的沙堆的最小归并方案。
用二维数组表示为:
刚开始犯了很多错,
比如先开始是这么写的(一脸蒙蔽):
1 for (int i=1;i<=n;i++) 2 for (int j=i+1;j<=n;j++) 3 for (int k=i;k<=j-1;k++) 4 f[i][j]=(f[i][j]>f[i][k]+f[k+1][j]+g[i][j])?f[i][k]+f[k+1][j]+g[i][j]:f[i][j];//未考虑递推关系
手动挥手.jpg
正解如下:
1 #include "iostream"
2 #include "cstdio"
3 #include "queue"
4 #define qwq 21000000
5 int n,m,q;
6 using namespace std;
7 int f[1000][1000];
8 int g[1000][1000];
9 int gra[1000],minn=-2100000;
10 int main()
11 {
12 int n;
13 cin>>n;
14 for (int i=1;i<=n;i++)
15 cin>>gra[i];
16
17 for (int i=1;i<=n;i++)
18 g[i][i]=gra[i];
19
20 for (int i=1;i<=n;i++)
21 for (int j=i+1;j<=n;j++)
22 g[i][j]=g[i][j-1]+gra[j];
23
24 for (int i=1;i<=n;i++)
25 for (int j=1;j<=n;j++)
26 f[i][j]=(i!=j)?qwq:0; //i -> j(i)的代价为 +∞(0)
27
28 for (int p=2;p<=n;p++)//穷举堆数//因为是递推(Recursion)所以从小堆数向大堆数
29 for (int i=1;i<=(n-p+1);i++)//一段的确定性(Certainty) 列举起点
30 {
31 int j=i+p-1; //终点(Destination)
32 for (int k=i;k<=j-1;k++)//穷举隔开位置 //注意超界所致的溢出(Overflow)
33 f[i][j]=(f[i][j]>f[i][k]+f[k+1][j]+g[i][j])?f[i][k]+f[k+1][j]+g[i][j]:f[i][j];//三目运算符不清楚的可以百度,下面也有简介
34 } //正确写出状态转移方程//无后效性 (Unfollow-up Effect)
35 cout<<f[1][n]<<endl;
36 }
动态规划真的是个神奇的东西,
它适合求解多阶段(状态转换)决策问题的最优解,也可用于含有线性或非线性递推关系的最优解问题。
但其实它并不全能,
1,最优化原理
2,无后效性
必须满足这两个条件才能用,
当然,
写动态规划最主要的是写出状态转移方程,
其次是边界条件。
附一:
三目运算符普遍的用处就是减少if语句的使用
例如:
1 i=(括号条件成立与否)?(成立):(不成立);
标签:
原文地址:http://www.cnblogs.com/RoitAGI/p/5665040.html