石子合併(三) 環形合併
阿新 • • 發佈:2019-02-12
題目描述
在一個園形操場的四周擺放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);
}