关于最小代价子母树

第一次尝试写动态规划(Dynamic Planning)=

问题如下:

-------------------------------------------------------------------------------------------------------------------------

最小代价子母树

设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的和称为总代价,给出一种归并算法,使总代价为最小.
输入、输出数据格式与“石子合并”相同。
输入样例:
4
12 5 16 4

-------------------------------------------------------------------------------------------------------------------------

为了说明算法的过程,我们先分析一些简单的情况:

(1)n=2:

当n=2时,仅有1种堆法,因此总的归并代价为2堆沙子的和。

(2)n=3:

当n=3时,有2种堆法。

第1种堆法的总代价为20+24,第2种堆法的总代价为11+24。由此可见,最后一次的归并代价为全部沙子数量的和,对任何归并方案都是相同的,因此总的代价将取决于第一次归并,第1种方法的第1次归并代价为20,第2种方法的第1次归并代价为11,因此第种方法比第1种好。

(3)n=4:

方法a总代价:20+34+40=94       方法b总代价:21+34+40=95    方法c总代价:20+20+40=80      方法d总代价:21+27+40=88

方法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=(括号条件成立与否)?(成立):(不成立);

时间: 2024-08-10 17:21:24

关于最小代价子母树的相关文章

最小代价 子母树

题目描述 Description 在一个操场上摆放着一排N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将N堆石子合并成一堆的最小得分. 输入描述 Input Description 第一行是一个数N. 以下N行每行一个数A,表示石子数目. 输出描述 Output Description 共一个数,即N堆石子合并成一堆的最小得分. 样例输入 Sample Input 4 1 1 1 1 样例输出 S

[swustoj 404] 最小代价树

最小代价树(0404) 问题描述 以下方法称为最小代价的字母树:给定一正整数序列,例如:4,1,2,3,在不改变数的位置的条件下把它们相加,并且用括号来标记每一次加法所得到的和. 例如:((4+1)+ (2+3))=((5)+(5))=10.除去原数不4,1,2,3之外,其余都为中间结果,如5,5,10,将中间结果相加,得到:5+5+10= 20,那么数20称为此数列的一个代价,若得到另一种算法:(4+((1+2)+3))=(4+((3)+3))=(4+(6))=10,数列的另一个代价为:3+6

[Swust OJ 404]--最小代价树(动态规划)

题目链接:http://acm.swust.edu.cn/problem/code/745255/ Time limit(ms): 1000 Memory limit(kb): 65535 Description 以下方法称为最小代价的字母树:给定一正整数序列,例如:4,1,2,3,在不改变数的位置的条件下把它们相加,并且用括号来标记每一次加法所得到的和. 例如:((4+1)+ (2+3))=((5)+(5))=10.除去原数不4,1,2,3之外,其余都为中间结果,如5,5,10,将中间结果相加

orderby工作原理 + 最小代价取随机数

orderby是如何工作的 场景例子:假设你要查询城市是"杭州"的所有人名字,并且按照姓名排序返回 前1000个人的姓名.年龄. 表结构: ? SQL语句:select city,name,age from t where city="杭州" order by name limit 1000; 全字段排序 Extra字段中Using filesort表示需要排序,mysql会给每个线程分配一块内存用于排序 执行流程 初始化sort_buffffer,确定放入name

最小代价生成树(数据结构)

1 //最小代价生成树 2 //prim算法(稠密图):从与这棵树相连的边中选择最短的边,并将这条边及其所连顶点接入当前树中 3 void Prim(MGraph g,int v0,int &sum) { 4 int lowcost[maxsize],visit[maxsize],v;//lowcost存放当前树到其他顶点的最小权值的顶点 5 int min,k; 6 v=v0; 7 for(int i=0; i<g.n; i++) { 8 lowcost[i]=g.edges[v0][i]

51nod 1125 交换机器的最小代价

基准时间限制:1 秒 空间限制:131072 KB 有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增.移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和.例如:3 2 1,交换1 3后为递增排序,总的交换代价为4.给出N台机器的重量,求将所有机器变为有序的最小代价.(机器的重量均为正整数) Input 第1行:1个数N,表示机器及房间的数量.(2 <= N <= 50000) 第2 - N + 1行:每行1个数,表示机器的重量Wi.(

括号序列的最小代价

题意 查看原题 这里有一个关于合法的括号序列的问题. 如果插入"+"和"1"到一个括号序列,我们能得到一个正确的数学表达式,我们就认为这个括号序列是合法的.例如,序列"(())()", "()"和"(()(()))"是合法的,但是")(", "(()"和"(()))("是不合法的.我们这有一种仅由"(",")"

实验六 最小代价生成树

实验名称:最小代价生成树 实验章节:算法设计与分析第6章 实验目的: 掌握贪心算法解决问题的思想和一般过程,           学会使用普里姆算法解决实际问题. 提交形式: 所有作业的原程序和可执行程序(即cpp文件和exe文件) 纸质实验报告(格式和内容请参阅末页) 实验内容 完善下列程序,并回答问题. 1 #include<iostream.h> 2 3 #define G_NODE_NUM 6 //结点个数 4 5 #define INFTY 65535 6 7 template<

POJ 3666 Making the Grade(数列变成非降序/非升序数组的最小代价,dp)

传送门: http://poj.org/problem?id=3666 Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9468   Accepted: 4406 Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would lik