zoukankan      html  css  js  c++  java
  • 石子合并(区间dp)

    题目描述

    在一个圆形操场的四周摆放 NNN 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

    试设计出一个算法,计算出将 NNN 堆石子合并成 111 堆的最小得分和最大得分。

    输入格式

    数据的第 111 行是正整数 NNN,表示有 NNN 堆石子。

    222 行有 NNN 个整数,第 iii 个整数 aia_iai 表示第 iii 堆石子的个数。

    输出格式

    输出共 222 行,第 111 行为最小得分,第 222 行为最大得分。

    输入输出样例

    输入 #1
    4
    4 5 9 4
    输出 #1
    43
    54

    说明/提示

    1N100,0≤ai≤200

    dp[i][j]为从第i个位置到第j个位置的最小(大)结果;可以看成两堆合并;

    只有两堆的时候,直接将两堆合并;当大于两堆的时候,最后也是将两个堆合并;

    由此:dp【i】【j】=min(dp[i][j],dp[i][mid]+dp[mid+1][j]+sum[j]-su[i-1]);

    最大好说,最小的话,右上三角要初始化为 一个较大数,但是对角线要初始化为0;

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int main(){
        int n;
        cin>>n;
        int a[205];
        int sum[205]={0};
        int dp1[205][205],dp2[205][205];
    //    memset(dp1,0,sizeof(dp1));
    //    memset(dp2,-1,sizeof(dp2));
        for(int i=1;i<=n;i++){
            cin>>a[i];
            a[n+i]=a[i];
        }
        for(int i=1;i<=2*n;i++){
            sum[i]=sum[i-1]+a[i];
            dp1[i][i]=0;
        }
        for(int i=1;i<=2*n;i++){
            for(int j=i;j<2*n;j++){
                if(j==i)dp1[i][j]=0;
                else dp1[i][j]=1000000;
            }
        }
    /*        for(int i=1;i<=2*n;i++){
            for(int j=1;j<=2*n;j++){
                cout<<dp1[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<"************"<<endl;    */
        for(int i=2;i<=n;i++){
            for(int l=1,r;l<2*n-i+1;l++){
            //    dp1[l][r]=100000;
            //    dp2[l][r]=-1;
                r=l+i-1;
                for(int mid=l;mid<r;mid++){
                    dp1[l][r]=min(dp1[l][r],dp1[l][mid]+dp1[mid+1][r]+sum[r]-sum[l-1]);
                    dp2[l][r]=max(dp2[l][r],dp2[l][mid]+dp2[mid+1][r]+sum[r]-sum[l-1]);
                }
            }
        }
    /*        for(int i=1;i<=2*n;i++){
            for(int j=1;j<=2*n;j++){
                cout<<dp1[i][j]<<" ";
            }
            cout<<endl;
        }*/
        int ans1=123456789,ans2=-1;
        for(int i=1;i<=n;i++){
            ans1=min(ans1,dp1[i][i+n-1]);
            ans2=max(ans2,dp2[i][i+n-1]);
        }
        cout<<ans1<<endl<<ans2<<endl;
    }

  • 相关阅读:
    MySQL命令行基本操作
    MYSQL多表查询笔记
    MYSQL事务笔记
    Linux测试环境部署相关命令和步骤
    Jmeter录制脚本
    办公软件通讯录排序相关测试点
    Burp Suite抓包App
    安全测试 Burp Suite抓包工具
    及时通信办公软件,验证码登录,获取验证码失败原因分析和规避方法
    redis内存溢出问题分析和后续规避方法
  • 原文地址:https://www.cnblogs.com/wtx2333/p/12363563.html
Copyright © 2011-2022 走看看