石子合併問題--直線版 HRBUST
阿新 • • 發佈:2018-12-24
一條直線上擺放著一行共n堆的石子。現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請編輯計算出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。
Input
輸入有多組測試資料。
每組第一行為n(n<=100),表示有n堆石子,。
二行為n個用空格隔開的整數,依次表示這n堆石子的石子數量ai(0<ai<=100)
Output
每組測試資料輸出有一行。輸出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。 中間用空格分開。
Sample Input
3
1 2 3
Sample Output
9 11
思路:合併這兩堆前,這兩堆已經得到的分數 + 合併這兩堆得的分數;列舉分割點,找出合併這兩堆前,這兩堆已經得到的分數的最大和最小;
程式碼:
#include<bits/stdc++.h> using namespace std; #define Max 110 #define ll long long #define INF 0x3f3f3f3f int sum[Max]; int dp1[Max][Max]; // 合併這兩堆前,這兩堆已經得到的分數 + 合併這兩堆得的分數; int dp2[Max][Max]; int n; int main() { while(~scanf("%d",&n)) { sum[0] = 0; memset(dp1,INF,sizeof(dp1)); memset(dp2,0,sizeof(dp2)); for(int i = 1;i <= n;i ++) { scanf("%d",&sum[i]); sum[i] +=sum[i-1]; dp1[i][i] = 0; } for(int len = 2;len <= n;len ++) { for(int i = 1,j = len; j <= n; i++ ,j++) { for(int k = i;k<=j-1;k++) // 列舉分割點; { dp1[i][j] = min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]); dp2[i][j] = max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]); } } } printf("%d %d\n",dp1[1][n],dp2[1][n]); } return 0; }