南郵 OJ 1225 石子合併問題
阿新 • • 發佈:2019-02-16
石子合併問題
時間限制(普通/Java) : 1000 MS/ 3000 MS 執行記憶體限制 : 65536 KByte總提交 : 151 測試通過 : 42
比賽描述
在一個圓形操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計一個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。
對於給定n堆石子,程式設計計算合併成一堆的最小得分和最大得分。
輸入
輸入的第1行是正整數n,1≤n≤100,有n堆石子。第二行有n個數,分別表示每堆石子的個數。
輸出
輸出的第 1行中的數是最小得分;第2行中的數是最大得分。
樣例輸入
4
4 4 5 9
樣例輸出
43
54
提示
undefined
題目來源
演算法設計與實驗題解
/* dp(i,j)表示從第i個開始,合併後面j個得到的最優值。 sum(i,j)表示從第i個開始直到i+j個的數量和 */ #include <iostream> #define MAXN 100 using namespace std; int sum[MAXN]; int mins[MAXN][MAXN]; int maxs[MAXN][MAXN]; int n,stone[MAXN]; int sums(int i,int j){ if(i+j<n){ return sum[i+j]-(i==0?0:sum[i-1]); } return sums(i,n-1-i) + sums(0,(i+j)%n); } void getBest(int& minnum, int& maxnum){ for(int i=0; i<n; ++i){ mins[i][0] = maxs[i][0] = 0; } for(int j=1;j<n;++j){ for(int i=0;i<n;++i){ mins[i][j] = INT_MAX; maxs[i][j] = 0; for(int k=0;k<j;++k){ mins[i][j] = min(mins[i][k]+mins[(i+k+1)%n][j-k-1]+sums(i,j),mins[i][j]); maxs[i][j] = max(maxs[i][k]+maxs[(i+k+1)%n][j-k-1]+sums(i,j),maxs[i][j]); } } } minnum = mins[0][n-1]; maxnum = maxs[0][n-1]; for(int i = 0; i < n; ++i){ minnum = min(minnum, mins[i][n-1]); //第i個開始,合併後面j個.i不一定是0 maxnum = max(maxnum, maxs[i][n-1]); } } int main(){ scanf("%d", &n); for(int i=0;i<n;++i) scanf("%d", &stone[i]); sum[0] = stone[0]; for(int i=1;i<n;++i){ sum[i] = sum[i-1]+stone[i]; } int minnum, maxnum; getBest(minnum, maxnum); printf("%d\n%d\n",minnum,maxnum); return 0; }