区间dp--P1880 [NOI1995]石子合并
状态:给你状态$f[i][j]$表示将i~j堆石子合并为一堆的最小/最大得分
转移方程:$f1[i][j] = max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j))$
$f2[i][j] = min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j))$;
规定一个划分线,$i$到$j$个石子所能得到的最大得分和最小得分,是$i$到$k$得到的最大分数或最小得分,加上$k+1$到$j$的最大分数或最小得分,再加上,合并后的到的分数的最大值和最小值。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 const int inf=0x3f3f3f; 6 int n,minl,maxl,f1[300][300],f2[300][300],num[300]; 7 int s[300]; 8 inline int d(int i,int j){return s[j]-s[i-1];} 9 int main() 10 { 11 scanf("%d",&n); 12 for(int i=1;i<=n;i++) 13 { 14 scanf("%d",&num[i]); 15 num[i+n]=num[i]; 16 } 17 for(int i=1;i<=2*n;i++) 18 { 19 s[i]=s[i-1]+num[i]; 20 } 21 for(int p=1;p<n;p++) 22 { 23 for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p) 24 { 25 f2[i][j]=inf; 26 for(int k=i;k<j;k++) 27 { 28 f1[i][j] = max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j)); 29 f2[i][j] = min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j)); 30 } 31 } 32 } 33 minl=inf; 34 for(int i=1;i<=n;i++) 35 { 36 maxl=max(maxl,f1[i][i+n-1]); 37 minl=min(minl,f2[i][i+n-1]); 38 } 39 printf("%d\n%d",minl,maxl); 40 return 0; 41 }