精华内容
下载资源
问答
  • 石子合并问题动态规划
    千次阅读
    2019-07-23 22:38:47

    问题描述:
    有 n 堆石子堆放在路边围成一个圆,现要将石子有序地合并成一堆,规定每次只能移动相邻的两堆石子合并,合并花费为新合成的一堆石子的数量。求将这 N 堆石子合并成一堆的总花费(最小或最大)。
    源代码:

    public class 石子合并 {

    public static int sum(int x[],int i,int j) {

    	int sum=0;
    	for(int a=i;a<=j;a++) {
    		sum+=x[a];
    	}
    	return sum;
    

    }

    public static int 合并(int x[]) {

    	int n=x.length;//石子总数
    	int sumx=1000;
    	int dp[][]=new int[n+1][n+1];
    	int s [][]=new int[n+1][n+1];
    	for(int i=0;i<s.length;i++) {
    		s[i][i]=i;
    		dp[i][i]=0;
    	}
    	for(int i=n-1;i>=0;i--) {
    		for(int j=i+1;j<n;j++) {
    			int temp=10000;
    			int fence=0;
    		    for(int k=s[i][j-1];k<=s[i+1][j];k++)
    		    {
    		    	int aaa=dp[i][k]+dp[k+1][j]+sum(x,i,j);
    		    	if(temp>aaa) {
    		    		temp=aaa;
    		    		fence=k;
    		    	}
    		    }
    		    s[i][j]=fence;
    		    dp[i][j]=temp;
    		}
    	}
    	System.out.println(dp[1][4]);//测试
    	for(int i=0;i<=n/2;i++) {
    		if(dp[i][i+n/2-1]<sumx)
    		sumx=dp[i][i+n/2-1];
    	}
    	return sumx;
    

    }

    public static void main(String args[]) {

    int x[]=new int[] {4,4,5,9,4,4,5,9};
    System.out.println(合并(x));
    

    }
    }

    更多相关内容
  • 分析:首先起始位置未知,不能随意根据最大或最小作为起始点,因为例如想求最大的,原理就是先找最大的,因为每个求和都把前面的和加一遍,所以此时前面的和最大才能求出后面的最大解,所以必须用for循环动态规划!...

    传送门
    分析:首先起始位置未知,不能随意根据最大或最小作为起始点,因为例如想求最大的,原理就是先找最大的,因为每个求和都把前面的和加一遍,所以此时前面的和最大才能求出后面的最大解,所以必须用for循环动态规划!
    接着要求是环状的,所以一定有首位相加的情况,此时就开一个2倍的数组,这样首尾就可以一起讨论了。
    3.求其递推方程
    其递推方程:m[i][j] = m[i][k]+m[k+1][j] + sum [j] - sum [i -1];
    4.递推方程的解释:
    前面的m[i][k] 和 m[k+1][j] :i到k合并成一堆,k+1到j又合并成一堆
    后面的sum[j] - sum[i -1]: 这里表示的是刚形成的两堆 再合并到一块的石子数
    也就是用前缀和来求区间和
    比如有(1,2,3,4,5,6)这里表示的是有6堆石子
    现在我们求m[3][6] = m[3][4]+m[5][6] + sum[6] - sum[2]

    							  sum[6]:表示的是将这6堆全部合并在一起 
    							  sum[2]:表示的是将前两堆合并在一起
    							  
    							  现在我们要求后4堆的和 那不就是sum[6] - sum [2]; 		 **
    

    ac代码:

    #include<stdio.h>
    #include<algorithm>
    using  namespace std;
    int a[410],sum[410],dp[410][410],dd[410][410];
    int inf=0x3f3f3f3f;
    int main()
    {
    	int n,i,j,t,ans1,ans2;
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		a[i+n]=a[i];
    		dp[i][i]=dd[i][i]=0;
    	}
    	for(i=1;i<=2*n;i++)
    	sum[i]=a[i]+sum[i-1];//求出前缀和,方便后边区间相加 
    	for(i=2;i<=n;i++)
    //区间长度,因为要从最小的区间开始求最小最大化,所以区间要从2开始控制 如果从1的话  循环完dp[1] dd[1]=inf,影响整体了 
    	for(j=1;j<=2*n-(i-1);j++)//起点位置,区间长度变化,起点也随着变化,防止越界 
    	{
    		int k=j+i-1;//末位置  
    		dd[j][k]=-inf;
    		dp[j][k]=inf;
    		for(t=j;t<k;t++)
    //从小区间开始,这样求出来才能推大区间 小区间不断变化 所以找一个中介点
    		{
    		dd[j][k]=max(dd[j][k],dd[j][t]+dd[t+1][k]+sum[k]-sum[j-1]);
    		dp[j][k]=min(dp[j][k],dp[j][t]+dp[t+1][k]+sum[k]-sum[j-1]);
    		}
    	}
    	ans1=-inf;
    	ans2=inf;
    	for(i=1;i<=n;i++)//i为起点,遍历出长度为n的环 
        {
    		ans1=max(dd[i][i+n-1],ans1);
    		ans2=min(dp[i][i+n-1],ans2);
    	}
    	printf("%d\n%d\n",ans2,ans1);	
    }
    
    展开全文
  • 解题思路:类似于矩阵连乘问题,可以用动态规划的方法来解决: (1)定义一个n*n的数组A来存储合并石子的最小合并方式,由一开始的只有两堆石子要合并慢慢向上递归得到n堆石子合并的最小得分。 (2)定义另一个...
  • 问题 思路 假设有 1 2 3 三堆石头 总代价计算如下: 我们看到总代价 必然包括 三堆石头的总和 6,剩下代价看 1-2 和2-3 哪个代价最小,那么总代价为6加上最小代价。 所以有公式 mm[1][3] = MIN(mm[1][2],mm[2][3]) ...

    问题

    在这里插入图片描述

    思路

    假设有 1 2 3 三堆石头 总代价计算如下:
    在这里插入图片描述

    我们看到总代价 必然包括 三堆石头的总和 6,剩下代价看 1-2 和2-3 哪个代价最小,那么总代价为6加上最小代价。
    所以有公式 mm[1][3] = MIN(mm[1][2],mm[2][3]) + sum(1,3)
    推广到一般式 mm[1][n] = MIN(mm[1][n-1],mm[2][n]) + sum(i,n)
    推广到一般式 mm[i][j] = MIN(mm[i][j-1],mm[i+1][j]) + sum(i,n)
    自然联想到矩阵连乘 从左下到右上 填写斜线,最后输出右上 即为结果。(与矩阵连乘不同,没有用到第三层的for循环,for(int k = i+1;k<j;k++)
    ——————————————————————
    以上是我第一次所想到的,好像是正确。
    ——————————————————————
    看 另一个 例子 1 2 3 1

    按照上面的公式可以得到下面的表格:
    在这里插入图片描述
    我们发现最终的结果为16,但是有可以比16更小的代价

    按上面的一般性的公式mm[1][4]
    = MIN(mm[1][3],mm[2][4]) +sum(1,4) => MIN(9,10)+7=16
    但是还有另一种可能如下:
    1+2=3 | 3+1=4 3+4+7=14

    也就是说

    mm[1][4]=
    mm[1][1] + mm[2][4] + sum(1,4) => 0 + 10 + 7 = 17
    mm[1][2] + mm[]3[4] + sum(1,4) => 3 + 4 + 7 = 14
    mm[1][3] + mm[]4[4] + sum(1,4) => 9 + 0 + 7= 16

    可以看到,对于上面推导的公式 mm[i][j] = MIN(mm[i][j-1],mm[i+1][j]) + sum(i,n) ,我以偏概全,认为1-3(i->(j-1)),4-4 (j->j)或者1-1 (i->i),2-4((i+1)j)
    1-4(i->j)的最小代价,
    还有一种情况
    1-2 (i->(j-2)) 3-4 ((i+2)->j)
    的代价更小,没有考虑进去。
    ————————————————————
    那么上面推导的公式就不正确了
    再次推导:
    mm[i][j]
    = MIN(mm[i][k]+mm[k+1][j])+sun(i,j) 其中 i<=k<=j

    至此我们发现 动态规划之石子合并问题与 动态规划之举证连乘就十分相似了,那就没多少说的了,直接码。

    实现

    import java.util.Scanner;
    
    public class CollectStone {
    	static int[] aa;
    	static int[][] mm;
    	public static void main(String[] args) {
    		Scanner sc  = new Scanner(System.in);
    		while(sc.hasNext()) {
    			int n = sc.nextInt();
    			aa = new int[n];
    			
    			for (int i = 0; i < n; i++) {
    				aa[i] = sc.nextInt();
    				
    			}
    			mm = new int[n+1][n+1];
    			solve(n);
    			System.out.println(mm[1][n]);
    		}
    
    	}
    	private static void solve(int n) {
    		for(int i=1;i<=n;i++) mm[i][i]=0;
    		
    		for (int r = 2; r <= n; r++) {
    			for (int i = 1; i <= n-r+1; i++) {
    				int j = i+r-1;
    				mm[i][j] = mm[i][i]+mm[i+1][j]+sum(i,j);
    				for (int k = i+1; k < j; k++) {
    					int t = mm[i][k]+mm[k+1][j]+sum(i,j);
    					if(t<mm[i][j]) {
    						mm[i][j] = t;
    					}
    				}
    				
    			}
    			
    		}
    	}
    	private static int sum(int i, int j) {
    		int sum=0;
    		for (int z = i-1; z <= j-1; z++) {
    			sum+=aa[z];
    		}
    		return sum;
    	}
    
    }
    
    

    在这里插入图片描述

    展开全文
  • 第一个石子合并模型,和书上3.1节的矩阵连乘问题类似. 假设m[i,j]为合并石子ai…aj, 1≤i≤j≤n,所得到的最小得分,若没有“合并”这个动作,则为0。原问题所求的合并最小值即为m[1,n]。 递推公式如下,其中min表示...
  • 1.问题描述在一个圆形操场的...2.动态规划or贪心算法动态规划:用来求解最优性质的解,将原问题划分为若干个子问题,先求解子问题的解,由子问题的解求出原问题的解。这些子问题往往不互相独立,所以我们用一个表...

    1.问题描述

    在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。

    2.动态规划or贪心算法

    动态规划:用来求解最优性质的解,将原问题划分为若干个子问题,先求解子问题的解,由子问题的解求出原问题的解。这些子问题往往不互相独立,所以我们用一个表(在具体代码中经常用数组)来存储子问题的解避免重复求解。动态规划需要满足的条件为最优子结构性质即问题的最优解所包含的子问题的解也是最优的。同时需要满足子问题的重叠性和无后效性即某状态以后的过程不会影响以前的状态,只与当前状态有关。

    贪心算法:同样用来求解具有最优性质的解,总是做出当前状态下的最优选择。希望得到的最终结果也是最优的。贪心算法求解最优解的条件有两个:贪心选择性质——问题的最优解可以通过局部最优解得到;最优子结构性质。

    动态规划和贪心算法的主要区别在于动态规划采用自底向上的方式求解问题,贪心算法则是采用自顶向下的方法进行求解,以迭代方式继续做出贪心选择,将问题规模变为规模更小的自问题。

    言归正传,石子合并问题是否可以采用贪心算法?以求得最小合并数为例,如果采用贪心算法,每次做的贪心选择为总是合并两个相邻的石子个数最小的两堆。假如有五堆石子数分别为:8 7 6 8 。

    第一次合并:8 7 6 8 。得分13

    第二次合并:8 13 8 。得分13+ 21

    第三次合并:21 8。得分13+21+29

    不采用贪心算法:

    第一次合并:8 7 6 8。得分15

    第二次合并:15 6 8。得分15+14

    第三次合并:15 14。得分15+14+29.(PS 最后一次得分总是石子总数sum,以后求解会用到)

    所以该问题求解不适用与贪心算法,其实贪心算法适用的问题不是很广泛,比较典型的有活动安排问题,线段覆盖问题,数字组合问题等。

    3.采用动态规划求解

    动态规划算法的求解步骤分为:划分阶段——>确定状态和状态变量——>找出状态转移方程——>找出递归结束条件。

    对于石子合并问题的问题阶段可分为:

    当合并的石子为一堆时候:分数为0

    当合并的石子为两堆时候:合并分数为相邻两堆石子的个数之和

    当合并的石子为三堆时候:合并分数为min(第i堆石子与第i+1石子合并的分数+三堆石子总数,第i+1堆石子与第i+2石子合并的分数+三堆石子总数);

    ...

    状态变量:m[i][j]第i堆至第j堆石子合并时候的分数,stone[i]表示第i堆石子个数

    状态转移方程:m[i][j]=min(m[i][k]+m[k+1][j]+sum);sum表示第i堆石子至第j堆石子总数,也是最后一次合并的分数

    4.代码实现

    #include

    #include

    #define N 1000

    using namespace std;

    //求最小合并堆数目

    //p[] 代表石头数目数组,n表示石堆数目

    int minNumber(int p[N],int n)

    {

    int i=1,j=1,k=1;//用来计数

    //定义二维数组m[i][j]来记录i到j的合并过程中的最少石子数目

    int **m;

    m=new int* [n];

    for(i=1;i<=n;i++)

    {

    m[i]=new int[n];

    }

    for(i=1;i<=n;i++)

    {

    for(;j<=n;j++)

    m[i][j]=-1;

    }

    int min=0;//记录合并最小值

    //单独合并

    for(i=1;i<=n;i++)

    m[i][i]=0;

    //相邻两堆石子合并

    for(i=1;i<=n-1;i++)

    {

    j=i+1;

    m[i][j]=p[i]+p[j];

    }

    //相邻三堆至最后的n堆

    for(k=3;k<=n;k++)

    {

    int sum=0;//记录k堆石子总数

    for(i=1;i<=n-k+1;i++)

    {

    j=i+k-1;//记录相邻r堆石子(第i个石子至第j个石子)合并

    //先求得这k堆石子的总数

    for(int x=i;x<=j;x++)

    sum+=p[x];

    //第一种情况

    m[i][j]=m[i+1][j]+sum;

    //计算i到k和k+1到j堆合并时候最小合并值,选择最小值

    for(int r=i+1;r<=j-1;r++)

    {

    int t=m[i][r]+m[r+1][j]+sum;

    if(t

    m[i][j]=t;

    }

    }

    }

    return m[1][n];

    }

    //求最大合并值

    int maxNumber(int p[],int n)

    {

    //记录生成最大合并值的过程中,从i到j合并的最大合并至

    int i=1,j=1,k=1;//用来计数

    int **m;

    m=new int* [n];

    for(i=1;i<=n;i++)

    {

    m[i]=new int[n];

    }

    for(i=1;i<=n;i++)

    for(;j<=n;j++)

    m[i][j]=-1;

    int max=0;

    //单独组合

    for(i=1;i<=n;i++)

    m[i][i]=0;

    //两两组合

    for(i=1;i<=n-1;i++)

    {

    j=i+1;

    m[i][j]=p[i]+p[j];

    }

    //相邻三堆至第n堆组合时

    for(k=3;k<=n;k++)

    {

    for(i=1;i<=n-k+1;i++)

    {

    int j=i+k-1;

    int sum=0;

    for(int r=i;r<=j;r++)

    sum+=p[r];

    m[i][j]=m[i+1][j]+sum;

    for(k=i+1;k

    {

    int t=m[i][k]+m[k+1][j]+sum;

    if(t>m[i][j])

    m[i][j]=t;

    }

    }

    }

    return m[1][n];

    }

    int main()

    {

    int stone[N];

    int min = N;

    int max = 0;

    int n;

    int i = 1,j=1;

    ifstream input("input.txt");

    ofstream output("output.txt");

    input >> n;

    while (!input.eof())

    {

    input >> stone[i];

    i++;

    }

    min = minNumber(stone, n);

    max = maxNumber(stone, n);

    for (; i <= n - 1; i++)

    {

    int min_temp = 0;

    int max_temp = 0;

    int temp = stone[1];

    for (int k = 2; k <= n; k++)

    {

    stone[k - 1] = stone[k];

    }

    stone[n] = temp;

    min_temp = minNumber(stone, n);

    max_temp = maxNumber(stone, n);

    if (min_temp 

    min = min_temp;

    if (max_temp > max)

    max = max_temp;

    }

    output <

    output <

    system("pause");

    }

    展开全文
  • 动态规划算法是计算机算法设计中的一个重要算法,通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推的方式去解决,石子合并问题作为典型算例,能够彰显动态规划算法特征 针对石子合并问题,本文利用...
  • 区间动态规划石子合并
  • 试设计算法,计算出将N堆石子合并成一堆的最小花费。在解题之前,介绍一下“四边形不等式优化”,关于这个优化方法的证明,csdn以及网上其他博客上详细介绍了很多,查了很多资料还是有点一知半解,再次归纳简述如下...
  • 石子合并问题

    2014-05-18 21:08:22
    石子合并问题 JAVA,动态规划,贪心算法
  • 本文主要内容: 1. 问题描述 2. 输入输出示例 3. 算法设计思想与算法描述 ...合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
  • C++石子合并问题动态规划

    万次阅读 多人点赞 2018-06-25 10:55:54
    规定每次只能选择相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 算法设计:试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 样例输入:由input.txt提供输入数据 样例...
  • 题目 在一个圆形操场的四周摆放着n堆石子。...我们知道链式的石子合并问题是相邻两堆之间可以合并,那么环形的和链式的区别就在于,环形的相当于是链式的头尾两堆也能合并 那么,我们只要解决,如何在链式的基础上.
  • 动态规划——石子合并问题

    千次阅读 多人点赞 2020-02-05 23:20:10
    石子合并问题分三类: 1、任意合并 2、相邻的才能合并且排成直线 3、相邻的才能合并且围成圈 1、贪心即可解决 2、直线型 合并石子直线型 对于区间dp问题,我们先要把它细分为区间 我们可以这样定义dp数组 dp[i][j]的...
  • 石子合并问题 Problem Description 在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算...
  • 简单对该问题进行分析,该问题属于最优解问题,其次,选择某堆石子进行合并时,会影响到其他石子堆的选择,看起来像是动态规划问题。下面沿着动态规划设计思路展开。 第一步:划分阶段。 只有一堆石子时候,由于无法...
  • 动态规划石子合并问题(Circle版)

    千次阅读 多人点赞 2020-05-22 23:22:40
    这个问题和普通的石子合并问题不同,简单的石子合并问题采用的是将石子线性排列并合并,但是这个问题要求石子按照圆圈排列,所以首尾两个石子是能够合并的。 这就不由得引起我们的思考,我们怎么才能让首尾也相邻呢?...
  • 石子合并问题动态规划

    千次阅读 多人点赞 2020-06-10 09:44:03
    =100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为该次合并的得分,编一程序,给出堆数n及每堆石子数(<=200); (1)选择一种合并石子的方案,使得做n-1次...
  • 动态规划合并石子

    千次阅读 多人点赞 2020-08-17 21:40:43
    动态规划——合并石子(C语言解) 第一次接触到动态规划是在斐波那契数列,那个时候还不知道动态规划的概念,由于数据量较小,直接用for循环就通过了,直到遇到了”合并石子“这道题目,百度过很多的文章都没看懂,...
  • 动态规划 解决 石子合并 问题动态规划 解决 石子合并 问题动态规划 解决 石子合并 问题
  • 动态规划:用来求解最优性质的解,将原问题划分为若干个子问题,先求解子问题的解,由子问题的解求出原问题的解。这些子问题往往不互相独立,所以我们用一个表(在具体代码中经常用数组)来存储子问题的解避免重复...
  • 3. 通过编程实现租用游艇问题石子合并问题,进一步理解动态规划方法解题的四个基本步骤。 2、实验内容 1. 租用游艇问题:长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,…,n。游客可在这些游艇出租站租用...
  • 1.石子合并问题 在一个圆形操场的四周摆放着n堆石子。现要将石子有序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。设计一个算法,计算出将n堆石子合并成一堆的...
  • 试设计出1个算法,计算出将N堆石子合并成1堆的最小花费和最大花费. 输入输出格式 输入格式: 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 输入示例 4 4 4 5 9 输出...
  • 石子合并问题是最经典的DP问题。首先它有如下3种题型: (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成 分析:当然...
  • 石子合并问题--动态规划;贪心

    万次阅读 多人点赞 2015-10-17 20:18:13
    石子合并问题石子合并问题是最经典的DP问题。首先它有如下3种题型: (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成...
  • 动态规划经典题——石子合并

    千次阅读 2020-07-12 02:35:33
    石子合并题目信息路边玩法操场玩法问题分析路边玩法操场玩法算法设计路边玩法操场玩法完美图解(以路边玩法为例)伪代码详解路边玩法操场玩法实战演练优化后代码1274:【例9.18】合并石子 题目信息 路边玩法 有n堆...
  • 石子合并 动态规划(环形)

    千次阅读 2017-12-04 15:22:06
    1、问题描述:问题来源 NWPU noj 1148 在一个圆形操场的四周摆放着n堆石子(n 4 4 5 9 score: 0 8 5 9 score: 8 13 9 score: 8 + 13 = 21 22 score: 8 + 13 + 22 = 43 2、输入 可能有多组测试数据。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,875
精华内容 3,150
关键字:

石子合并问题动态规划