DP之石子堆合并问题
(1)相邻:在一个圆形操场的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。选择一种合并石子的方案,使得做n-1次合并,得分的总和最小。
/*
* 在一个圆形操场的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。
* 规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
*选择一种合并石子的方案,使得做n-1次合并,得分的总和最小。
*/
public static void test(int[]a) {
//b[i][j]表示i-j相加之和,求出每一斜列的最小值就是这一步相加
int[][]b=new int[a.length][a.length];
//赋初值
for(int i=0;i<a.length;i++) {
b[i][i]=a[i];
System.out.print(a[i]+" ");
}
int sum=0;
System.out.println("score:"+sum);
for(int r=1;r<=a.length-1;r++) {
int min=b[1][r]+b[0][0];
int index1=0,index2=r;
b[0][r]=min;
for(int i=1;i<a.length-r;i++) {
int j=i+r;
b[i][j]=b[i+1][j]+b[i][i];
if(b[i][j]<min) {
min=b[i][j];
index1=i;
index2=j;
}
} for(int i=0;i<a.length;i++) {
if(i<index1||i>index2) {
System.out.print(a[i]+" ");
}else if(i==index1){//出现最小值
System.out.print(min+" ");
}
}
sum+=min;
System.out.println("score:"+sum);
}
}
思路就是类似矩阵连乘,关键就是最优解不好表示或者我写的有问题。。。(明天再来改!!!今天累了)Ok得出结论了就是我的想法有问题。
下面是标准DP:
设dp[i][j]表示第i到第j堆石子合并的最优值(合并i-j的花费的最小力气),sum[i][j]表示第i到第j堆石子的总数量。那么就有状态转移公式:
因为每一个石子堆无非是和左边合并或者先和右边合并。对第i到第j的每一个k(子问题)计算他们的最小值加上每堆石子的总数量因为最后一步总是把所有的都合并。
我们可以从最小问题想起来:假如这个数组只有三个数,那么最小力气就是min(左边两个,右边两个)+三个的总量(最后一步)
有四个数时,将它们分为1-3,2-4两个子问题再继续分...
public static void testA(int[]a) {
class Point{
int start;
int end;
public Point(int start, int end) {
this.start = start;
this.end = end;
}
}
//b[i][j]表示第i堆到第j堆的最优合并值
int[][]b=new int[a.length][a.length];
//s表示i到j的和
int[][]s=new int[a.length][a.length];
//保存最优解 0左 1下
int[][]l=new int[a.length][a.length];
Stack<Point> stack=new Stack<Point>();
//赋初值
for(int i=0;i<a.length;i++) {
b[i][i]=0;
s[i][i]=a[i];
}
for(int r=1;r<=a.length-1;r++) {
for(int i=0;i<a.length-r;i++) {
int j=i+r;
s[i][j]=s[i][j-1]+s[j][j];
if(b[i][j-1]<b[i+1][j]) {//左边小
b[i][j]=b[i][j-1]+s[i][j];
l[i][j]=0;
}else {//下边小
b[i][j]=b[i+1][j]+s[i][j];
l[i][j]=1;
}
}
}
int x=0,y=a.length-1;
for(int i=0;i<a.length;i++) {
stack.add(new Point(x,y));
if(l[x][y]==0)//左边
y--;
else
x++;
}
while(!stack.isEmpty()) {
Point p=stack.pop();
for(int i=0;i<a.length;i++) {
if(i<p.start||i>p.end)
System.out.print(a[i]+" ");
else if(i==p.start)
System.out.print(s[p.start][p.end]+" ");
}
System.out.println("score:"+b[p.start][p.end]);
}
}
(2)环形:就是不是相邻的是成环的
最简单的就是穷举相邻的找出最小的。这个时候把上面函数的返回值设为int然后计算。
第二种方法是将两边各扩展一位。因为只和左右相关边界位置应与头尾相连,然后进行相同的计算,最后在几种方案中挑出最小的。
public static void testB(int[]a) {
class Point{
int start;
int end;
public Point(int start, int end) {
this.start = start;
this.end = end;
}
}
//首尾相连
int[]b=new int[a.length+2];
b[0]=a[a.length-1];
b[b.length-1]=a[0];
for(int i=0;i<a.length;i++) {
b[i+1]=a[i];
}
//i-j的最优
int[][]d=new int[b.length][b.length];
//sum
int[][]s=new int[b.length][b.length];
//最优解0左 1下
int[][]l=new int[b.length][b.length];
Stack<Point> stack=new Stack<Point>();
//赋初值
for(int i=0;i<b.length;i++) {
d[i][i]=0;
s[i][i]=b[i];
}
//可以不填满,只填到需要的就行
int min=-1;
Point end=new Point(-1,-1);
for(int r=1;r<=a.length-1;r++) {
for(int i=0;i<b.length-r;i++) {
int j=i+r;
s[i][j]=s[i][j-1]+s[j][j];
if(d[i][j-1]<d[i+1][j]) {//左边
d[i][j]=d[i][j-1]+s[i][j];
l[i][j]=0;
}else {//下边
d[i][j]=d[i+1][j]+s[i][j];
l[i][j]=1;
}
if(r==a.length-1) {//找到最小的那个的值并记录解
if(min==-1)
{
min=d[i][j];
end.start=i;
end.end=j;
}
else if(min>d[i][j])
{
min=d[i][j];
end.start=i;
end.end=j;
}
}
}
}
int x=end.start,y=end.end;
for(int i=0;i<a.length;i++) {
stack.add(new Point(x,y));
if(l[x][y]==0)//左边
y--;
else
x++;
}
while(!stack.isEmpty()) {
Point p=stack.pop();
for(int i=0;i<a.length;i++) {
if(i<p.start||i>p.end)
System.out.print(b[i]+" ");
else if(i==p.start)
System.out.print(s[p.start][p.end]+" ");
}
System.out.println("score:"+d[p.start][p.end]);
}
}
(3)总结
这个是典型的DP问题,因为已经处理过之前的矩阵连乘问题,所以一开始我陷入了固定思维只想着填表,而没有去找子问题一步一步来。本末倒置。导致思路很不清晰但是代码似乎更简短。在处理环形时,选取了在两边扩展一位再每次分组计算最后取出一部分。
DP之石子堆合并问题的更多相关文章
- dp入门 石子相邻合并 详细带图讲解
题目: 有N堆石子,现要将石子有序的合并成一堆,规定如下: 1.每次只能移动相邻的2堆石子合并 2.合并花费为新合成的一堆石子的数量. 求将这N堆石子合并成一堆的总花费最小(或最大). 样例: 输入 ...
- UESTC 886 方老师金币堆 --合并石子DP
环状合并石子问题. 环状无非是第n个要和第1个相邻.可以复制该行石子到原来那行的右边即可达到目的. 定义:dp[i][j]代表从第i堆合并至第j堆所要消耗的最小体力. 转移方程:dp[i][j]=mi ...
- 区间DP经典 石子合并
题目链接 题意:环形的一群石子,每次可以选择相邻的两堆合并,分数为新得到的一堆石子,求将这片石子合并成一堆的最大和最小分数 输入:第一行一个正整数n,其后n个数代表每堆石子的个数 分析:第一次写的时候 ...
- nyoj737区间dp(石子合并)
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的 ...
- 区间dp之 "石子合并"系列(未完结)
A. 石子合并<1> 内存限制:128 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统评测 方式:文本比较 题目描述 有N堆石子排成一排(n<=100),现要将石 ...
- 整数划分——区间dp(石子合并)
这不是将一个数以一来划分,而是把一个整数以位来划分 题目描述 如何把一个正整数N(N长度<20)划分为M(M>1)个部分,使这M个部分的乘积最大.N.M从键盘输入,输出最大值及一种划分方式 ...
- 2017北京网络赛 J Pangu and Stones 区间DP(石子归并)
#1636 : Pangu and Stones 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In Chinese mythology, Pangu is the fi ...
- hihocoder1636 Pangu and Stones(区间DP(石子合并变形))
题目链接:http://hihocoder.com/problemset/problem/1636 题目大意:有n堆石头,每次只能合并l~r堆,每次合并的花费是要合并的石子的重量,问你合并n堆石子的最 ...
- dp——环形石子合并(区间dp)
环形的解决很巧妙 #include <iostream> #include <cstring> #include <string> #include <map ...
随机推荐
- 基于Python的Webservice开发(四)-泛微OA的SOAP接口
一.功能需求 泛微e-cology可以在流程中调用Webservice接口实现与其他系统的联动等复杂功能.但是目前泛微文档中仅提供了调用的方法,但是没有关于接口的相关开发信息. 本次案例是用Pytho ...
- PHP函数:json_last_error
json_last_error() - 返回 JSON 编码解码时最后发生的错误.. 说明: json_last_error ( void ) : int 参数: 无 返回值: 返回一个整型(int ...
- 极验反爬虫防护分析之slide验证方式下图片的处理及滑动轨迹的生成思路
本文要分享的内容是去年为了抢鞋而分析 极验(GeeTest)反爬虫防护的笔记,由于篇幅较长(为了多混点CB)我会按照我的分析顺序,分成如下四个主题与大家分享: 极验反爬虫防护分析之交互流程分析 极验反 ...
- 掌握游戏开发中类Message、Handle
1. 实验目的 1. 自主地设计图形界面 2. 掌握消息类Message的应用 3. 掌握消息处理类Handle的应用 4. 掌握子线程中中更新UI界面的方法 2. 实验内容 1. 在主界面设置 ...
- Java 反射调用方法 - 不跳过安全检查、跳过安全检查和普通方法性能比较测试
java中反射提供灵活性同时,给运行效率带来了一定影响.写个代码测试一下 package com.xzlf.reflectTest; import java.lang.reflect.Method; ...
- Java 学习线路图
学习是一个循序渐进的过程,是一件非常难得坚持的事情.如果真的想学Java,一定要下定决心! 这里我分享给你的Java学习线路图,希望对你有帮助,以下为2020年更新版本,黑马君在2020年更新了Jav ...
- (第九篇)Iptables详解
常见的网络攻击形式 1.拒绝服务攻击:DOS 2.分布式拒绝服务攻击 DDOS 3.漏洞入侵 4.口令猜测 以上内容简单了解,具体可自行百度,此处不必知晓. Linux防火墙基础 Linux防火墙体系 ...
- Inno Setup [Run] Section 双引号嵌套
https://stackoverflow.com/questions/26257808/inno-setup-how-to-run-a-code-procedure-in-run-section-o ...
- 如何在没有安装 Python 的机器上运行 Python 程序
cmd 命令 1. pip install pyinstaller 2. pyinstaller <path to your prog.py> 3. 应用程序在prog.py同路径下的 d ...
- Linux利用sed批量修改文件名
初始文件名 # ls -lh total 5.5G -rw-r--r-- 1 root root 193K Sep 28 09:38 20180908.txt drwxr-xr-x 2 root ro ...