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 ...
随机推荐
- The equation SGU - 106
题目链接:https://codeforces.com/problemsets/acmsguru/problem/99999/106 这个题是关于EXGCD特别好的一个题目.题目大意:有一个等式ax+ ...
- B2. Character Swap (Hard Version)
链接: http://codeforces.com/contest/1243/problem/B2 题目大意: 两个字符串,判断能否通过交换为从而使得这两个字符串完全一致,如不可以的话,直接输出NO, ...
- 带权值的图 BFS
用bfs遍历最图求最短路径时通常借用优先队列即优先考虑最大的或者最小的权值 方法1 优先队列:(内置函数,优先考虑较小的权值) #include<iostream> #include< ...
- Eclipse Hadoop源码阅读环境
一.解压hadoop src包到workspace目录.为加快下载jar包的速度,在eclipse的maven设置里将配置文件的路径设置正确,然后配置maven的settings.xml: <m ...
- django基础(一) - 安装和配置文件
django介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C. <div style='color: red'> ...
- Neo4J 查找两节点之间的路径
# 两节点之间的所有路径MATCH p=(a)-[*]->(b)RETURN p # a->b 直接连接MATCH p=(a)-[]->(b)RETURN p # a-...> ...
- react: typescript interface useState issue
define interface: interface ILoginState { imageId: string; imageSrc: string; username: string; passw ...
- 移植madplay到ARM板
一.环境和软件介绍 1.主机环境:Ubuntu16.04 2.交叉编译器: gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) 3.ARM板:kernel: ...
- 如何快速地恢复你的win10
win10清单 这份List不会介绍如何安装系统,而是当面对一个新系统,如何最快的搭建,或者说恢复到一个生产力环境. 必备习惯 备份软件安装包和常用内容上云是高效恢复的两点关键. 备份软件安装包 我的 ...
- Spring Cloud微服务技术概览
Spring Cloud 是一系列框架的有序集合.它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载均衡.断路器.数据监控等,都 ...