石子归并的三种打开方式——难度递增———51Node

N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 
Input
第1行:N(2 <= N <= 100)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxx=105;
const int INF=0x3f3f3f3f;
int n,num[maxx],dp[maxx][maxx],sum[maxx][maxx];
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                sum[i][j]=sum[i][j-1]+num[j];
            }
        }
        memset(dp,INF,sizeof(dp));
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                if(i>=j){
                    dp[i][j]=0;
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=i-1;j>=1;j--){
                for(int k=j;k<i;k++){
                    dp[j][i]=min(dp[j][i],dp[j][k]+dp[k+1][i]+sum[j][i]);
                }
            }
        }
        printf("%d\n",dp[1][n]);
    }
    return 0;
}
View Code
基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 
N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 
Input
第1行:N(2 <= N <= 1000)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>

using namespace std;
const int N=2005;
int n,f[N][N]={0},a[N][N]={0};
int s[N][N];
int main(){
    memset(f,1,sizeof(f));
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i][i]);
        a[n+i][n+i]=a[i][i];
    }
    for(int i=0;i<n*2;i++){
        s[i][i]=i;
        f[i][i]=0;
    }
    for(int i=0;i<n*2-1;i++){
        for(int j=i+1;j<n*2-1;j++){
            a[i][j]=a[i][j-1]+a[j][j];
        }
    }
    for(int l=1;l<n;l++){
        for(int i=0;i+l<n*2-1;i++){
            int j=i+l;
            for(int k=s[i][j-1];k<=s[i+1][j];k++){
                if(f[i][j] > a[i][j]+f[i][k]+f[k+1][j])
                {
                    f[i][j] = a[i][j]+f[i][k]+f[k+1][j];
                    s[i][j] = k;
                }
            }
        }
    }
    int ans=f[0][n-1];
    for(int i=1;i<n;i++){
        if(ans>f[i][i+n-1]){
            ans=f[i][i+n-1];
        }
    }
    printf("%d\n",ans);
    return 0;


}
View Code
基准时间限制:2 秒 空间限制:131072 KB 分值: 320 难度:7级算法题
 
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 
Input
第1行:N(2 <= N <= 50000)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 50005;

int stone[N];
long long  n,t,ans;

void combine(int k)
{
    int tmp = stone[k] + stone[k-1];
    ans += tmp;
    for(int i=k;i<t-1;i++)
        stone[i] = stone[i+1];
    t--;
    int j = 0;
    for(j=k-1;j>0 && stone[j-1] < tmp;j--)
        stone[j] = stone[j-1];
    stone[j] = tmp;
    while(j >= 2 && stone[j] >= stone[j-2])
    {
        int d = t - j;
        combine(j-1);
        j = t - d;
    }
}

int main()
{
    while(scanf("%lld",&n)!=EOF)
    {
        if(n == 0) break;
        for(int i=0;i<n;i++)
            scanf("%d",stone+i);
        t = 1;
        ans = 0;
        for(int i=1;i<n;i++)
        {
            stone[t++] = stone[i];
            while(t >= 3 && stone[t-3] <= stone[t-1])
                combine(t-2);
        }
        while(t > 1) combine(t-1);
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2018-05-25 12:09  buerdepepeqi  阅读(501)  评论(2编辑  收藏  举报