1148環形石子合併
1148.石子合併
時限:1000ms 記憶體限制:10000K 總時限:3000ms
描述
在一個圓形操場的四周擺放著n堆石子(n<= 100),現要將石子有次序地合併成一堆。規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,讀入石子堆數n及每堆的石子數(<=20)。選擇一種合併石子的方案,使得做n-1次合併,得分的總和最小;比如有4堆石子:4 4 5 9 則最佳合併方案如下: 4 4 5 9 score: 0 8 5 9 score: 8 13 9 score: 8 + 13 = 21 22 score: 8 + 13 + 22 = 43
輸入
可能有多組測試資料。 當輸入n=0時結束! 第一行為石子堆數n(1<=n<=100);第二行為n堆的石子每堆的石子數,每兩個數之間用一個空格分隔。
輸出
合併的最小得分,每個結果一行。
輸入樣例
4 4 4 5 9 0
輸出樣例
43
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,minh,minm; int a[210]; int m[210][210];//m[i][j]記錄從第i個到第j個石子堆合併的最小得分 int sum(int i,int j) { int s=0; for(int k=i;k<=j;k++) { s+=a[k]; } return s; } int minscore() { int t; for(int i=1;i<=2*n-1;i++) { m[i][i]=0; } for(int i=1;i<2*n-1;i++) { m[i][i+1]=a[i]+a[i+1];//相鄰兩個合併的和 } for(int i=2;i<=2*n-1;i++)//表示間隔大小 { for(int j=1;j<=2*n-1-i;j++)//1 3 2 4 3 5 4 6 { //計算m[j][i+j]的最小值 minh=m[j+1][i+j]+a[j]+sum(j+1,i+j); for(int k=1;k<i;k++) { if(j+k+1==i+j) { t=m[j][j+k]+sum(j,j+k)+a[i+j]; } else { t=(m[j][j+k]+m[j+k+1][i+j])+sum(j,j+k)+sum(j+k+1,i+j); } if(minh>t) { minh=t;
} } m[j][i+j]=minh; } } minm=99999999; for(int i=1;i<=2*n-n;i++) { if(m[i][i+n-1]<minm) { minm=m[i][i+n-1]; }
} return minm; } int main() { while(cin>>n) { if(n==0)break; memset(a,0,sizeof(a)); memset(m,0,sizeof(m)); for(int i=1;i<=n;i++) { cin>>a[i]; } for(int i=1;i<=n-1;i++) { a[i+n]=a[i]; } cout<<minscore()<<endl; } return 0; }