1. 程式人生 > >石子合併(三) 環形合併

石子合併(三) 環形合併

題目描述

在一個園形操場的四周擺放N堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,合併的花費為這相鄰兩堆之和

試設計出1個演算法,計算出將N堆石子合併成1堆的最小花費.

輸入輸出格式

輸入格式:
資料的第1行試正整數N,1≤N≤100,表示有N堆石子.第2行有N個數,分別表示每堆石子的個數.

輸出格式:
輸出最小得分

題解:
動態規劃
dp[i][t]=min(dp[i][t],dp[i][k]+dp[(i+k-1)%n+1][t-k]+sum(i,t))

dp[ i ][ t ]表示從 i開始之後t堆石子合併花費。 則求dp[ i ][ n ]的最小解,1<=i<=n;

可以把dp[ i ][ n ]看成一堆,這一堆的最優解是由 由這堆分割的兩小堆合併的。
這兩小堆分別是多大才才能得到最優解,要列舉。 在列舉的過程中將各個值儲存起來,就是動態規劃。

例如4堆過程:
初始化 dp[i][1]=0 ;此時還沒有合併,沒有花費
第一次合併得:dp[ 1 ][ 2 ],dp[ 2 ][ 2 ],dp[ 3 ][ 2 ],dp[ 4 ][ 2 ],及12,23,34,41;

第二次合併得:dp[ 1 ][ 3 ],dp[ 2 ][ 3 ],dp[ 3 ][ 3 ],dp[ 4 ][ 3 ],及123,234,341,412;

第三次合併得:dp[ 1 ][ 4 ],dp[ 2 ][ 4],dp[ 3 ][ 4 ],dp[ 4 ][ 4 ],及1234,2345,3412,4123;

合併過程中用dp[i][t]=min(dp[i][t],dp[i][k]+dp[(i+k-1)%n+1][t-k]+sum(i,t))求值

#include<stdio.h>
#include<string.h>
#define Ma_x 99999
#define min(a,b) a<b?a:b

int n,w[205],dp[205][205];

int sum(int i,int t){//從i開始t個石堆合併的花費 
    int k,s=0,k1;
    for(k=i;k<i+t;k++){
        k1=k%n;
        if
(k1==0) k1=n; s=s+w[k1]; } return s; } int main(){ int i,t,k; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&w[i]); dp[i][1]=0;//還沒合併,不需花費 } //核心演算法,動態規劃 for(t=2;t<=n;t++){ for(i=1;i<=n;i++){ dp[i][t]=Ma_x; for(k=1;k<t;k++){ dp[i][t]=min(dp[i][t],dp[i][k]+dp[(i+k-1)%n+1][t-k]+sum(i,t)); } } } int mini=Ma_x; for(i=1;i<=n;i++){//從第幾堆石子開始結果最小 mini=min(mini,dp[i][n]); } printf("%d ",mini); }