环形石子合并

Description
在一个 圆形操场 的四周摆放 N 堆石子 (N≤100) ,现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。编一程序,读入堆数 N 及每堆石子数 (≤100) 选择一种合并石子的方案,分别得到合并这 N 堆石子为一堆,可以得到的最大得分和最小得分
Input
输入包含多个例子。第一行为 N ,即石子堆的数目,以下一行为 N 个整形,分别代表每堆石子的数目。当 N=0 时,输入结束。
Output
对每个例子,输出其最小得分和最大得分,这两个数值以空格间隔开,每个例子占一行。
Sample Input
6
30 35 15 5 10 20
3
1 2 3333
6
3 4 5 6 7 8
0
Sample Output
275 475
3339 6671
84 125
Hint


分析 : 动态规划的典型题目。 从合并相邻两个堆开始,三个堆。。。。一直到N个堆。

   由于是环形,我延长了数组长度,用来将环形变换成线性。


以下代码

/*

*/
#include <bits/stdc++.h>
using namespace std ;
#define N 100
int dp[N*2][N*2] ; // dp(i,j) 表示第i堆石子到第j堆石子的合并后的最优值
int getCount(int a[],int i, int j){
    int sum = 0 ;
    for (;i<=j;++i)
        sum+=a[i] ;
    return sum ;
}
int getMaxScore(int a[] , int Num){

    memset(dp,0,sizeof dp);
    int maxscore = 0 ;
    for (int l = 1; l < Num ;++l){//l 是合并后的长度
            for (int i = 0 ; i < Num*2-1 ; ++i){// i 是合并的起始位置
                if (i+l>=2*Num-1)
                    continue;
                int count = getCount(a,i,i+l);
                for (int k = 0 ; k < l ;  k++ ){ //k代表合并时 第一堆的数量
                    dp[i][i+l] = max(dp[i][i+l] , dp[i][i+k]+dp[i+k+1][i+l]+count);
                  //  printf("i=%d , k = %d , j = %d, dp=%d\n",i,k,i+l,dp[i][i+l]);
                }
            }
    }
    for (int i =0 ; i < Num ;++i){
        maxscore = max(maxscore , dp[i][i+Num-1]) ;
    }
    return maxscore;
}
int getMinScore(int a[] , int Num){
    memset(dp,0,sizeof dp);
    int maxscore = 0x7fffffff ;

   // cout<<"max"<<maxscore<<endl;
    for (int l = 1; l < Num ;++l){//l+1 是合并后的长度
            for (int i = 0 ; i < Num*2-1 ; ++i){// i 是合并的起始位置
                if (i+l>=2*Num-1)
                    continue;
                int count = getCount(a,i,i+l);
              //  cout<<"count :"<<count <<endl;
                dp[i][i+l] = 0x7fffffff;
                for (int k = 0 ; k < l ;  k++ ){ //k代表合并时 第一堆的数量

                    dp[i][i+l] = min(dp[i][i+l] , dp[i][i+k]+dp[i+k+1][i+l]+count);
                  //  printf("i=%d , k = %d , j = %d, dp=%d\n",i,k,i+l,dp[i][i+l]);
                }
            }
    }
    for (int i =0 ; i < Num ;++i){
        maxscore = min(maxscore , dp[i][i+Num-1]) ;
    }
    return maxscore;
}
int main(){

    int Num ;
    int s[N];
    while (cin>>Num&& Num!=0){
        for (int i = 0 ; i < Num ; ++i){
            cin>> s[i];
            s[i+Num] = s[i] ;
        }
        cout<<"minscore "<<getMinScore(s,Num)<<endl;
        cout<<"maxscore "<<getMaxScore(s,Num)<<endl;

    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值