环形石子合并
Description
在一個圓形操場的四周擺放N堆石子(N≤100),現要將石子有次序地合并成一堆。規定每次只能選相鄰的兩堆合并成新的一堆,并將新的一堆的石子數,記為該次合并的得分。編一程序,讀入堆數N及每堆石子數(≤100)選擇一種合并石子的方案,分別得到合并這N堆石子為一堆,可以得到的最大得分和最小得分
Input
輸入包含多個例子。第一行為N,即石子堆的數目,以下一行為N個整形,分別代表每堆石子的數目。當N=0時,輸入結束。
Output
對每個例子,輸出其最小得分和最大得分,這兩個數值以空格間隔開,每個例子占一行。
Sample Input
6
30 35 15 5 10 20
3
1 2 3333
6
3 4 5 6 7 8
0
Sample Output
275 475
3339 6671
84 125
Hint
無
分析 : 動態規劃的典型題目。 從合并相鄰兩個堆開始,三個堆。。。。一直到N個堆。
? ?由于是環形,我延長了數組長度,用來將環形變換成線性。
以下代碼
/**/ #include <bits/stdc++.h> using namespace std ; #define N 100 int dp[N*2][N*2] ; // dp(i,j) 表示第i堆石子到第j堆石子的合并后的最優值 int getCount(int a[],int i, int j){int sum = 0 ;for (;i<=j;++i)sum+=a[i] ;return sum ; } int getMaxScore(int a[] , int Num){memset(dp,0,sizeof dp);int maxscore = 0 ;for (int l = 1; l < Num ;++l){//l 是合并后的長度for (int i = 0 ; i < Num*2-1 ; ++i){// i 是合并的起始位置if (i+l>=2*Num-1)continue;int count = getCount(a,i,i+l);for (int k = 0 ; k < l ; k++ ){ //k代表合并時 第一堆的數量dp[i][i+l] = max(dp[i][i+l] , dp[i][i+k]+dp[i+k+1][i+l]+count);// printf("i=%d , k = %d , j = %d, dp=%d\n",i,k,i+l,dp[i][i+l]);}}}for (int i =0 ; i < Num ;++i){maxscore = max(maxscore , dp[i][i+Num-1]) ;}return maxscore; } int getMinScore(int a[] , int Num){memset(dp,0,sizeof dp);int maxscore = 0x7fffffff ;// cout<<"max"<<maxscore<<endl;for (int l = 1; l < Num ;++l){//l+1 是合并后的長度for (int i = 0 ; i < Num*2-1 ; ++i){// i 是合并的起始位置if (i+l>=2*Num-1)continue;int count = getCount(a,i,i+l);// cout<<"count :"<<count <<endl;dp[i][i+l] = 0x7fffffff;for (int k = 0 ; k < l ; k++ ){ //k代表合并時 第一堆的數量dp[i][i+l] = min(dp[i][i+l] , dp[i][i+k]+dp[i+k+1][i+l]+count);// printf("i=%d , k = %d , j = %d, dp=%d\n",i,k,i+l,dp[i][i+l]);}}}for (int i =0 ; i < Num ;++i){maxscore = min(maxscore , dp[i][i+Num-1]) ;}return maxscore; } int main(){int Num ;int s[N];while (cin>>Num&& Num!=0){for (int i = 0 ; i < Num ; ++i){cin>> s[i];s[i+Num] = s[i] ;}cout<<"minscore "<<getMinScore(s,Num)<<endl;cout<<"maxscore "<<getMaxScore(s,Num)<<endl;}return 0; }
總結
- 上一篇: ORA-00910: specified
- 下一篇: 设计模式的形象比喻