美文网首页动态规划
石子合并问题

石子合并问题

作者: Super_邓帅 | 来源:发表于2016-12-31 20:10 被阅读312次


石子合并动态规划解决

在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选择相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
测试用例:
4(石子的堆数)
4 4 5 9(每一堆的石子数目)
输出: 43 54

分析:

首先,注意这是圆形的操场,石子堆圆形摆放,也就是最后一堆石子可以和第一堆石子合并,可以通过不同石子堆分别打头排列,解决这个问题。
  因为用的方法是动态规划,所以肯定要为数组首先打好底,这样后续操作才能在此基础上进行。
  此题与矩阵连乘问题相比,先计算每一堆石子自己合并的情况(这就是数组打底),然后一个循环,r控制2堆,3堆,4堆.......n堆石子合并;每i堆石子合并的时候,需要控制起始位置,i代表从哪一堆开始合并,j代表到哪一堆合并结束。
  这样,i,j就控制了一个范围,在这个范围内分成r堆合并。但究竟r在哪个地方分开,才能获得最优值,我们是不知道的,需要i,j范围都遍历看一看。
  还有就是递推公式,类比矩阵连乘问题理解,i到k的计算量+k到j的计算量+i到j的石子总数,就是当前m[i][j]的值,代表i堆到j堆合并的最大(最小)得分。

#include<stdio.h>
#define n 4   // 4堆石子 
int stone[n]={4,4,5,9};

int Max(){
    int m[n][n]={0};   //m[i][j]是i堆到j堆合并的最大得分 
    int i,j,k,r,t;
    int sum=0;   //i堆到j堆的石子数 
    //每一堆自己合并
    for(i=0;i<n;i++)
        m[i][i]=0; 
    //两堆以上合并
    for(r=2;r<=n;r++){
        for(i=0;i<=n-r;i++){
            j=i+r-1;
            sum=0;
            for(k=i;k<=j;k++)
                sum+=stone[k];
            m[i][j]=m[i][i]+m[i+1][j]+sum;
            for(k=i+1;k<j;k++){
                t=m[i][k]+m[k+1][j]+sum;
                if(t>m[i][j])
                    m[i][j]=t;
            }        
        }
    }
    return m[0][n-1];
}

int Min(){
    int m[n][n]={0};   //m[i][j]是i堆到j堆合并的最大得分 
    int i,j,k,r,t;
    int sum=0;   //i堆到j堆的石子数 
    //每一堆自己合并
    for(i=0;i<n;i++)
        m[0][0]=0; 
    //两堆以上合并
    for(r=2;r<=n;r++){
        for(i=0;i<=n-r;i++){
            j=i+r-1;
            sum=0;
            for(k=i;k<=j;k++)
                sum+=stone[k];
            m[i][j]=m[i][i]+m[i+1][j]+sum;
            for(k=i+1;k<j;k++){
                t=m[i][k]+m[k+1][j]+sum;
                if(t<m[i][j])
                    m[i][j]=t;
            }        
        }
    }
    return m[0][n-1];
}
int main(){
    int max=0,min=10000;
    int temp=0,tmax,tmin; 
    for(int i=0;i<n;i++){
        temp=stone[0];               //因为是圆形的,不断轮换,每个元素都打头,
        for(int j=0;j<n-1;j++){      //就实现了最后一堆石子和第一堆的合并
            stone[j]=stone[j+1];
        }
        stone[n-1]=temp;
        tmax=Max();
        tmin=Min();
        if(tmax>max)
            max=tmax;
        if(tmin<min)
            min=tmin;
    } 
    printf("最大:%d\n最小:%d\n",max,min);   
    return 0;
} 
运行截图

相关文章

  • 石子合并问题

    石子合并动态规划解决 在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选择相邻的两堆...

  • 腾讯校招-石子合并-c++

    初始一共有n堆石子,每堆石子有w[i]个石子,对石子堆进行合并,每次任意选取两堆石子进行合并。一堆有x个石子的石子...

  • LintCode-区间型动态规划石子归并

    石子归并 有一个石子归并的游戏。最开始的时候,有n堆石子排成一列,目标是要将所有的石子合并成一堆。合并规则如下: ...

  • [区间dp]石子合并(洛谷P1880)

    传送门 石子合并 AC代码

  • 石子合并 --- 动态规划

    1.分析题目现要将石子有次序地合并成一堆,要求&条件:规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数...

  • 区间DP

    石子合并 原题链接[https://www.acwing.com/problem/content/284/] 2....

  • 2018-12-26

    问题列表 合并两个有序链表 合并K个排序链表 合并区间 插入区间 问题与反馈 总结与收获 多个有序链表的合并,类似...

  • DP模板之---区间DP

    一.经典例题 题目地址: 【P1880】[NOI1995]石子合并 - 洛谷 二.分析 转移方程 dp_max[i...

  • 前端笔记——CSS常见问题及解决方案

    问题一:外边距合并问题 问题描述:外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的...

  • 小技巧合集之css

    01 修改placeholder样式 02 margin合并/塌陷问题解决方法 具体详见:margin合并/塌陷问题

网友评论

    本文标题:石子合并问题

    本文链接:https://www.haomeiwen.com/subject/vhkbvttx.html