• 相邻
  • 环形
  • 总结

(1)相邻:在一个圆形操场的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。选择一种合并石子的方案,使得做n-1次合并,得分的总和最小。

 1 /*2      * 在一个圆形操场的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。3      * 规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。4      *选择一种合并石子的方案,使得做n-1次合并,得分的总和最小。5      */6     public static void test(int[]a) {7         //b[i][j]表示i-j相加之和,求出每一斜列的最小值就是这一步相加8         int[][]b=new int[a.length][a.length];9         //赋初值
10         for(int i=0;i<a.length;i++) {
11             b[i][i]=a[i];
12             System.out.print(a[i]+" ");
13         }
14         int sum=0;
15         System.out.println("score:"+sum);
16         for(int r=1;r<=a.length-1;r++) {
17             int min=b[1][r]+b[0][0];
18             int index1=0,index2=r;
19             b[0][r]=min;
20             for(int i=1;i<a.length-r;i++) {
21                 int j=i+r;
22                 b[i][j]=b[i+1][j]+b[i][i];
23                 if(b[i][j]<min) {
24                     min=b[i][j];
25                     index1=i;
26                     index2=j;
27                 }
28             }
29
30             for(int i=0;i<a.length;i++) {
31                 if(i<index1||i>index2) {
32                     System.out.print(a[i]+" ");
33                 }else if(i==index1){//出现最小值
34                     System.out.print(min+" ");
35                 }
36             }
37             sum+=min;
38             System.out.println("score:"+sum);
39         }
40     }

思路就是类似矩阵连乘,关键就是最优解不好表示或者我写的有问题。。。(明天再来改!!!今天累了)Ok得出结论了就是我的想法有问题。

下面是标准DP:

设dp[i][j]表示第i到第j堆石子合并的最优值(合并i-j的花费的最小力气),sum[i][j]表示第i到第j堆石子的总数量。那么就有状态转移公式: 

因为每一个石子堆无非是和左边合并或者先和右边合并。对第i到第j的每一个k(子问题)计算他们的最小值加上每堆石子的总数量因为最后一步总是把所有的都合并。

我们可以从最小问题想起来:假如这个数组只有三个数,那么最小力气就是min(左边两个,右边两个)+三个的总量(最后一步)

有四个数时,将它们分为1-3,2-4两个子问题再继续分...

 1 public static void testA(int[]a) {2         class Point{3             int start;4             int end;5             public Point(int start, int end) {6                 this.start = start;7                 this.end = end;8             }9         }
10         //b[i][j]表示第i堆到第j堆的最优合并值
11         int[][]b=new int[a.length][a.length];
12         //s表示i到j的和
13         int[][]s=new int[a.length][a.length];
14         //保存最优解 0左 1下
15         int[][]l=new int[a.length][a.length];
16         Stack<Point> stack=new Stack<Point>();
17         //赋初值
18         for(int i=0;i<a.length;i++) {
19             b[i][i]=0;
20             s[i][i]=a[i];
21         }
22
23         for(int r=1;r<=a.length-1;r++) {
24             for(int i=0;i<a.length-r;i++) {
25                 int j=i+r;
26                 s[i][j]=s[i][j-1]+s[j][j];
27                 if(b[i][j-1]<b[i+1][j]) {//左边小
28                     b[i][j]=b[i][j-1]+s[i][j];
29                     l[i][j]=0;
30                 }else {//下边小
31                     b[i][j]=b[i+1][j]+s[i][j];
32                     l[i][j]=1;
33                 }
34             }
35         }
36         int x=0,y=a.length-1;
37         for(int i=0;i<a.length;i++) {
38             stack.add(new Point(x,y));
39             if(l[x][y]==0)//左边
40                 y--;
41             else
42                 x++;
43         }
44
45         while(!stack.isEmpty()) {
46             Point p=stack.pop();
47             for(int i=0;i<a.length;i++) {
48                 if(i<p.start||i>p.end)
49                     System.out.print(a[i]+" ");
50                 else if(i==p.start)
51                     System.out.print(s[p.start][p.end]+" ");
52             }
53             System.out.println("score:"+b[p.start][p.end]);
54         }
55     }

(2)环形:就是不是相邻的是成环的

最简单的就是穷举相邻的找出最小的。这个时候把上面函数的返回值设为int然后计算。

第二种方法是将两边各扩展一位。因为只和左右相关边界位置应与头尾相连,然后进行相同的计算,最后在几种方案中挑出最小的。

 1 public static void testB(int[]a) {2         class Point{3             int start;4             int end;5             public Point(int start, int end) {6                 this.start = start;7                 this.end = end;8             }9         }
10         //首尾相连
11         int[]b=new int[a.length+2];
12         b[0]=a[a.length-1];
13         b[b.length-1]=a[0];
14         for(int i=0;i<a.length;i++) {
15             b[i+1]=a[i];
16         }
17
18         //i-j的最优
19         int[][]d=new int[b.length][b.length];
20         //sum
21         int[][]s=new int[b.length][b.length];
22         //最优解0左 1下
23         int[][]l=new int[b.length][b.length];
24         Stack<Point> stack=new Stack<Point>();
25         //赋初值
26         for(int i=0;i<b.length;i++) {
27             d[i][i]=0;
28             s[i][i]=b[i];
29         }
30         //可以不填满,只填到需要的就行
31         int min=-1;
32         Point end=new Point(-1,-1);
33         for(int r=1;r<=a.length-1;r++) {
34             for(int i=0;i<b.length-r;i++) {
35                 int j=i+r;
36                 s[i][j]=s[i][j-1]+s[j][j];
37                 if(d[i][j-1]<d[i+1][j]) {//左边
38                     d[i][j]=d[i][j-1]+s[i][j];
39                     l[i][j]=0;
40                 }else {//下边
41                     d[i][j]=d[i+1][j]+s[i][j];
42                     l[i][j]=1;
43                 }
44                 if(r==a.length-1) {//找到最小的那个的值并记录解
45                     if(min==-1)
46                         {
47                         min=d[i][j];
48                         end.start=i;
49                         end.end=j;
50                         }
51                     else if(min>d[i][j])
52                         {
53                         min=d[i][j];
54                         end.start=i;
55                         end.end=j;
56                         }
57                 }
58             }
59         }
60         int x=end.start,y=end.end;
61         for(int i=0;i<a.length;i++) {
62             stack.add(new Point(x,y));
63             if(l[x][y]==0)//左边
64                 y--;
65             else
66                 x++;
67         }
68         while(!stack.isEmpty()) {
69             Point p=stack.pop();
70             for(int i=0;i<a.length;i++) {
71                 if(i<p.start||i>p.end)
72                     System.out.print(b[i]+" ");
73                 else if(i==p.start)
74                     System.out.print(s[p.start][p.end]+" ");
75             }
76             System.out.println("score:"+d[p.start][p.end]);
77         }
78     }

(3)总结

这个是典型的DP问题,因为已经处理过之前的矩阵连乘问题,所以一开始我陷入了固定思维只想着填表,而没有去找子问题一步一步来。本末倒置。导致思路很不清晰但是代码似乎更简短。在处理环形时,选取了在两边扩展一位再每次分组计算最后取出一部分。

DP之石子堆合并问题相关推荐

  1. 有n堆石子,每次取出两堆合成一堆,每堆石子的个数即为合并石子所需要耗费的体力,求出合并所有石子堆所需要耗费的最小体力

    有n堆石子,每次取出两堆合成一堆,每堆石子的个数即为合并石子所需要耗费的体力,求出合并所有石子堆所需要耗费的最小体力 典型的贪心题,即每次取出数量最少的两堆石子合并. 举个例子来说,假如有5堆石子,石 ...

  2. 浅谈几种常用二叉堆合并

    前言 可合并的堆有二叉堆.二项堆.配对堆.斐波那契堆等,光是二叉堆的合并就有无脑启发式合并.左偏树.斜堆等做法. 这里主要讲的是二叉堆,想了解其它优秀的可并堆可以看看DSCN上优秀的博客. 启发式合并 ...

  3. POJ 3017 DP + 单调队列 + 堆

    题意:给你一个长度为n的数列,你需要把这个数列分成几段,每段的和不超过m,问各段的最大值之和的最小值是多少? 思路:dp方程如下:设dp[i]为把前i个数分成合法的若干段最大值的最小值是多少.dp转移 ...

  4. 上课睡觉(合并石子问题)

    有 NN 堆石子,每堆的石子数量分别为 a1,a2,-,aN. 你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第2,3 堆石子,则石子堆集 ...

  5. 【动态规划】小石子游戏-石子合并

    题目 一群小孩子在玩小石子游戏,游戏有两种玩法. (1)路边玩法 有n堆石子堆放在路边,现要将石子有序地合并成一堆,规定每次只能移动相邻的两堆石子合并,合并花费为新合成的一堆石子的数量.求将这N堆石子 ...

  6. 取石头游戏 c语言,[HNOI2010]取石头游戏(博弈论+贪心)

    题目描述: 有\\(n\\)堆石子,每堆石子的个数为\\(a_i\\),保证存在至少一堆石子个数为\\(0\\) 两个人,每个人每次可以取一堆石子,一堆石子可以被取当且仅当它相邻的石子有至少一堆为\\ ...

  7. Java算法:牛客网腾讯笔试真题算法Java版1-11题

    题号 题目 知识点 难度 通过率 QQ1 生成格雷码 递归 简单 22.61%QQ2 微信红包 模拟 简单 25.61%QQ3 编码 字符串模拟 中等 26.60%QQ4 游戏任务标记 模拟 中等 3 ...

  8. 题:上课睡觉(暴力枚举)

    有 N 堆石子,每堆的石子数量分别为 a1,a2,-,aN 你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子,则石子堆集合 ...

  9. 上课睡觉-数论+枚举

    题目描述: 有 N 堆石子,每堆的石子数量分别为 a1,a2,-,aN. 你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子 ...

  10. Acwing4366上课睡觉

    有 N 堆石子,每堆的石子数量分别为 a1,a2,-,aN. 你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子,则石子堆集 ...

最新文章

  1. PRT(Precomputed Radiance Transfer)球谐光照(Spherical Harmonic Lighting)
  2. 对异步脉冲信号的处理——不归0翻转电路
  3. python中国余数定理_Python实现的中国剩余定理算法示例
  4. Android中focusable属性的妙用——底层按钮的实现
  5. 割平面法只能求解纯整数规划吗_离散规划 解法
  6. 求职产品经理【十六】笔试真题串讲之百度地图与大数据结合的产品
  7. mybatis分页的一种解决方案
  8. 联动椰树花式营销 完成债务重组的瑞幸又“站”了起来
  9. Unitest框架的使用(二)Unittest断言及应用
  10. 【Java程序设计】类与对象的基本概念(下)
  11. 奇异的Pinvoke调用
  12. windows下使用wineshark分析抓取本地回环包
  13. 大家一起写mvc(二)
  14. Zend Optimizer not installed可能原因及解决方法
  15. webstorm开发工具找回被误删除的代码
  16. PS动感映像插件ImageMotion 1.3中文汉化版
  17. mt管理器图片在哪个文件夹_MT管理器构造(新手小白教程)-小白文件管理器
  18. 推荐9款便签云生成工具
  19. 自用frp服务器分享及客户端配置连接教程
  20. linux bridge 抓包,Linux bridge hairpin mode

热门文章

  1. 假设法求最大值和数组的优点
  2. webstorm添加*.vue文件代码提醒支持webstorm支持es6vue里支持es6写法
  3. vue组件(Vue+webpack项目实战系列之三)
  4. 高效而轻松的sed命令
  5. hdu 1426(DFS+坑爹的输入输出)
  6. php常量的声明和使用
  7. Installing .NET Core on Ubuntu-摘自网络
  8. html5 职工入职后台管理系统_后台管理平台
  9. 拓端tecdat|R语言中绘制ROC曲线和PR曲线
  10. (7)数据结构-基本队列实现