1. 程式人生 > >石子合併 (區間DP)

石子合併 (區間DP)

一.試題
在一個園形操場的四周擺放N堆石子(N≤100),現要將石子有次序地合併成一堆。規定
每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。
編一程式,由檔案讀入堆數N及每堆的石子數(≤20),
①選擇一種合併石子的方案,使得做N-1次合併,得分的總和最小;
②選擇一種合併石子的方案,使得做N-1次合併,得分的總和最大。
例如,所示的4堆石子,每堆石子數(從最上面的一堆數起,順時針數)依
次為4594。則3次合併得分總和最小的方案:8+13+22=43
得分最大的方案為:14+18+22=54
</pre><pre name="code" class="cpp">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 105
//定義二維陣列m[i][j]來記錄i到j的合併過成中最少石子數目
int solve_min(int *p,int n)
{
    int i,j,k,r,sum;
    int m[N][N];
    memset(m,-1,sizeof(m));
    for(i=1; i<=n; i++)   //當一個單獨合併時,m[i][i]設為0,表示沒有石子
        m[i][i]=0;
    for(i=1; i<n; i++)  //當相鄰的兩堆石子合併時,此時的m很容易可以看出是兩者之和
        m[i][i+1]=p[i]+p[i+1];
    for(r=3; r<=n; r++) //當相鄰的3堆以及到最後的n堆時,執行以下迴圈
    {
        for(i=1; i<=n-r+1; i++)
        {
            j=i+r-1;
            sum=0;
            for(k=i; k<=j; k++)   //當i到j堆石子合併時最後裡面的石子數求和得sum
                sum+=p[k];
            m[i][j]=m[i+1][j]+sum;
// 此時m[i][j]為i~j堆石子間以m[i][i]+m[i+1][j]+sum結果,這是其中一種可能,不一定是最優
            for(k=i+1; k<j; 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 solve_max(int *p,int n)
{
    int i,j,k,r,sum;
    int m[N][N];
    memset(m,-1,sizeof(m));
    for(i=1; i<=n; i++)
        m[i][i]=0;
    for(i=1; i<n; i++)
        m[i][i+1]=p[i]+p[i+1];
    for(r=3; r<=n; r++)
    {
        for(i=1; i<=n-r+1; i++)
        {
            j=i+r-1;
            sum=0;
            for(k=i; k<=j; k++)
                sum+=p[k];
            m[i][j]=m[i+1][j]+sum;
            for(k=i+1; k<j; 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 i,j,k,n,stone[N];
    while(scanf("%d",&n)!=-1)
    {
        for(i=1; i<=n; i++)
        {
            scanf("%d",&stone[i]);
        }
        int mmin=solve_min(stone,n);
        int mmax=solve_max(stone,n);
        for(j=1; j<n; j++)
        {
            int t=stone[1];
            for(k=1; k<n; k++)
            {
                stone[k]=stone[k+1];
            }
            stone[n]=t;
            int tmin=solve_min(stone,n);
            int tmax=solve_max(stone,n);
            if(tmin<mmin)
                mmin=tmin;
            if(tmax>mmax)
                mmax=tmax;
        }
        printf("%d\n%d\n",mmin,mmax);
    }
    return 0;
}


相關推薦

[NOI1995]石子合併區間DP

題目連結: [NOI1995]石子合併   思路: 區間DP經典例題,可以把前n-1堆石子一個個移到第n個後面,那樣環就變成了線,即現在有2*n-1堆石子需要合併。   程式碼: #include <iostream> #include

石子合併 區間DP

一.試題在一個園形操場的四周擺放N堆石子(N≤100),現要將石子有次序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,由檔案讀入堆數N及每堆的石子數(≤20),①選擇一種合併石子的方案,使得做N-1次合併,得分

nyoj737—石子合併區間DP

描述     有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過N-1次合併後成為一堆。求出總的代價最小值。 輸入 有多組測試資料,輸入到檔案結束

區間dp*2】洛谷 P1880 [NOI1995]石子合併 推導過程 +尼克的任務還沒寫

emmmmm給自己設定了一個習慣界限。其實每次看到他們在做啥啥啥而我都大三都現在了  就會感覺很內傷-、- 不過演算法還是要寫的吧 別寫太多而已... 為了防止腦袋空空 也為了防止一天不知道幹什麼 ================================== &

石子合併問題 區間dp

石子合併問題是最經典的DP問題。首先它有如下3種題型:(1)有N堆石子,現要將石子有序的合併成一堆,規定如下:每次只能移動任意的2堆石子合併,合併花費為新合成的一堆石子的數量。求將這N堆石子合併成一堆

NYOJ題目737石子合併區間dp

石子合併(一) 時間限制:1000 ms  |  記憶體限制:65535 KB 難度:3 描述    有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將

51Nod - 1021 石子歸並區間DP

put -c ring 輸出 define .org max print left 【題目描述】 N堆石子擺成一條線。現要將石子有次序地合並成一堆。規定每次只能選相鄰的2堆石子合並成新的一堆,並將新的一堆石子數記為該次合並的代價。計算將N堆石子合並成一堆的最小代價。

nyoj 737 石子合並區間DP

using lac padding gin height space outline style 每次 737-石子合並(一) 內存限制:64MB 時間限制:1000ms 特判: No通過數:28 提交數:35 難度:3 題目描

【51nod 1021】石子歸併區間dp入門

1021 石子歸併 基準時間限制:1 秒 空間限制:131072 KB 分值: 20 難度:3級演算法題 收藏 關注 N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將N堆石子合併成一堆的最小代價。

石子歸併區間dp & 四邊形不等式優化

基準時間限制:1 秒 空間限制:131072 KB 分值: 20 難度:3級演算法題  收藏  取消關注 N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能

LightOJ - 1422 Halloween Costumes 區間DP

wan things strong cas book article printf ase con Description Gappu has a very busy weekend ahead of him. Because, next weekend is Ha

POJ 1141 Brackets Sequence 區間DP

ive bsp rip mes character har typedef som memset Description Let us define a regular brackets sequence in the following way: 1.

Brackets Sequence POJ - 1141 區間dp

gif == urn ++ char img ems utc pre Brackets Sequence POJ - 1141 題意:給一個括號序列,問最少添加多少個括號似的原序列匹配,並輸出新序列。 用dp[i][j]表示i到j最少添加幾個括號,flag[i][j]表

Brackets POJ - 2955 區間dp

pla clu for eof %d img rac end racket Brackets POJ - 2955 題意:給一個括號序列,問最多有多少個括號是可以配對的。 1 #include<cstdio> 2 #include<algori

Food Delivery ZOJ - 3469 區間dp

位置 turn pro pan return isp ive != truct Food Delivery ZOJ - 3469 題意:快遞員送外賣,n個客戶,起始位置為x,速度為v,每個客戶單位時間不滿意度增加hi,問最少增加多少不滿意度。 每一個客戶可能是從左側送到

CSUOJ-1980 不堪重負的數區間dp

inline 滿二叉樹 -a ems ext div des button problems 1980: 不堪重負的樹 Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Subm

POJ 1991 Turning in Homework區間DP

clu sin highlight sort stream ret spa 作業 ref 題目鏈接 Turning in Homework 考慮區間DP f[i][j][0]為只考慮區間[i, j]且最後在a[i]位置交作業的答案。 f[i][j][1]為只考慮區間[

hdu6212 祖瑪區間DP

tro 位置 表示 中間 ron i+1 strong 就會 題意 題意   有一個長度為n的01串,我們可以在某個地方插入一個0或者1,那麽如果有連續顏色相同的>=3個,那麽這段就會消去,兩邊的合攏。問將所有01串消去,最少需要插入多少個。(n<=200)

括號匹配問題區間dp

最小值 很好 nbsp 需要 簡單的 棧模擬 pri tex 什麽 簡單的檢查括號是否配對正確使用的是棧模擬,這個不必再說,現在將這個問題改變一下:如果給出一個括號序列,問需要把他補全成合法最少需要多少步? 這是一個區間dp問題,我們可以利用區間dp來解決,直接看代碼吧!

修長城 區間DP

urn ret 世紀 log width hide 時間 main gif Time Limit: 1000 ms Memory Limit: 256 MB Description   大家都知道,長城在自然條件下會被侵蝕,因此,我們需要修復。現在是21世紀,