洛谷 P1880 [NOI1995]石子合並
阿新 • • 發佈:2019-02-10
mina 輸出格式 eof badge span max for 輸入 size
題目描述
在一個圓形操場的四周擺放N堆石子,現要將石子有次序地合並成一堆.規定每次只能選相鄰的2堆合並成新的一堆,並將新的一堆的石子數,記為該次合並的得分。
試設計出1個算法,計算出將N堆石子合並成1堆的最小得分和最大得分.
輸入輸出格式
輸入格式:
數據的第1行試正整數N,1≤N≤100,表示有N堆石子.第2行有N個數,分別表示每堆石子的個數.
輸出格式:
輸出共2行,第1行為最小得分,第2行為最大得分.
輸入輸出樣例
輸入樣例#1:4
4 5 9 4
輸出樣例#1: 43
54
解題思路:
一道環形DP,f[i][j]表示i到j這一段合並成一堆的最大值,f[i][j] = max(f[i][j], f[i][k] + f[k][j] + sum[i+1][j]) i<=k<j,對於環形的處理是把這個環復制,接到末尾,其中sum[i+1][j]表示a[i] + a[i+1] + .. + a[j].
AC代碼:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 int n,f1[210][210],f2[210][210],num[210],maxans,minans = 9999999,he[105];//f1為最大值,f2為最小值 6 int max(int a,int b) { 7 if(a >= b) return a; 8 else return b; 9 } 10 int min(int a,int b) {11 if(a <= b) return a; 12 else return b; 13 } 14 int main() 15 { 16 cin >> n; 17 memset(f2,0x7f7f7f,sizeof(f2));//將最小值初始位足夠大 18 for(int i = 1; i <= n; i++) {//讀入 19 scanf("%d",&num[i]); 20 he[i] = he[i-1] + num[i]; 21 f2[i][i] = 0; 22 } 23 for(int i = n+1; i <= n+n; i++) {//將這個環復制一遍接到末尾 24 num[i] = num[i-n]; 25 he[i] = he[i-1] + num[i]; 26 f2[i][i] = 0; 27 } 28 for(int p = 1; p < n; p++)//枚舉區間長度 29 for(int i = 1, j = i + p; i < n + n && j < n + n; i++, j = i + p)//枚舉起點和終點 30 for(int k = i; k < j; k++){//設置斷點 31 f1[i][j] = max(f1[i][j], f1[i][k] + f1[k+1][j] + he[j] - he[i-1]);//狀態轉移 32 f2[i][j] = min(f2[i][j], f2[i][k] + f2[k+1][j] + he[j] - he[i-1]);//狀態轉移 33 } 34 35 for(int i = 1; i <= n; i++) {//找最大值和最小值 36 maxans = max(maxans,f1[i][i+n-1]); 37 minans = min(minans,f2[i][i+n-1]); 38 } 39 printf("%d\n%d",minans,maxans); 40 41 42 return 0; 43 }
洛谷 P1880 [NOI1995]石子合並