ssl1597-石子合併問題【區間dp練習】
在一個圓形操場的四周擺放著n 堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2 堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計一個演算法,計算出將n堆石子合併成一堆的最小得分和最大得分。
程式設計任務:
對於給定n堆石子,程式設計計算合併成一堆的最小得分和最大得分。
Input
輸入包括多組測試資料,每組測試資料包括兩行。
第1 行是正整數n,1<=n<=100,表示有n堆石子。
第2行有n個數,分別表示每堆石子的個數。
Output
對於每組輸入資料,輸出兩行。
第1 行中的數是最小得分;第2 行中的數是最大得分。
Sample Input
4
4 4 5 9
Sample Output
43
54
解題思路
看這題之前請補一下:http://blog.csdn.net/mr_wuyongcong/article/details/78815773
這道題是石子合併的升級版,這裡把改成了圓形,那麼說明第一堆和最後一堆也可以合併,這道題我用了一種不同的方法。可以先把所有兩個的和在一起,再把所有的三個的合在一起......以此類推。然後列出動態轉移方程:
mins=min(mins,f[i][k]+f[k+1][j]+s[j]-s[i-1])
maxs=max(maxs,f1[i][k]+f1[k+1][j]+s[j]-s[i-1])
還是程式碼講的清楚
程式碼
#include<cstdio>
#include<iostream>
using namespace std;
int n,x,s[201],f[201][201],f1[201][201],maxs,mins,a[201];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[n+i]=a[i];//環狀相連
}
for (int i=1;i<=2*n;i++)
s[i]=s[i-1]+a[i];//預處理不解釋
for (int ii=2;ii<=n;ii++)//如我所說↑
for (int i=1;i<=2*n-ii+1;i++)//列舉開頭
{
int mins=2147483647,maxs=0,j=i+ii-1;//如我所說↑
for (int k=i;k<j;k++)//列舉分裂點
{
mins=min(mins,f[i][k]+f[k+1][j]+s[j]-s[i-1]);
maxs=max(maxs,f1[i][k]+f1[k+1][j]+s[j]-s[i-1]);
//動態轉移方程
}
f[i][j]=mins;//最小值存入
f1[i][j]=maxs;//最大值存入
}
int mins=2147483647,maxs=0;
for (int i=1;i<=n;i++)
{
maxs=max(maxs,f1[i][i+n-1]); //求每個區域的最大值
mins=min(mins,f[i][i+n-1]); //求每個區域的最小值
}
printf("%d\n%d",mins,maxs);//get√
}