石子合并——环形dp、区间dp

P1880 [NOI1995] 石子合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道石子合并和之前的石子合并不一样。之前的那道题是一排石子合并,这道题是石子围成一圈合并。

那么问题就来了,围成一圈怎么进行合并处理呢?

以最大值为例,首先我们要明确,最后求得的是所有堆石子合并后的最大值。那么这个最大值满足最大值包含的每一区间都是该区间的最大值。可以反证,假设有一个区间的最大值不是这个最大值包含的那个区间最大值,那么累加之后的最大值应该大于原本的最大值。所以,问题就转化成求每一区间的最大值,最终就是所求的最大值。

 

注意1:因为石子围成了一圈,所以数组应该是个环,所以遍历的时候应该是从1到2n,并且前缀和应该从1到2n都算出来。

注意2:最后求的最值应该是for循环从1到n遍历一遍,maxx=max(maxx,f[i][i+n-1])这样的,因为是从1到n都要堆在一起。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=400;
 4 int a[N],s[N],f1[N][N],f2[N][N];
 5 
 6 int main()
 7 {
 8     int n;scanf("%d",&n);
 9     for(int i=1;i<=n;i++)
10     {
11         scanf("%d",&a[i]);
12         a[i+n]=a[i];
13     }
14     for(int i=1;i<=2*n;i++)
15         s[i]=s[i-1]+a[i];
16     
17     for(int len=1;len<=n;len++)
18     {
19         for(int i=1,j=len+i-1;i<=2*n,j<=2*n;i++,j=len+i-1)
20         {
21             if(i==j)
22             {
23                 f1[i][j]=0;
24                 f2[i][j]=0;
25                 continue;
26             }
27             f2[i][j]=0x3f3f3f3f;
28             for(int k=i;k<j;k++)
29             {
30                 f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+s[j]-s[i-1]);
31                 f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+s[j]-s[i-1]);
32             }
33         }
34     }
35     
36     int minn=0x3f3f3f3f,maxx=-1;
37     for(int i=1;i<=n;i++)
38     {
39         minn=min(minn,f2[i][i+n-1]);
40         maxx=max(maxx,f1[i][i+n-1]);
41     }
42     printf("%d\n%d\n",minn,maxx);
43     
44     return 0;
45 }
View Code

 

posted @ 2022-04-04 18:58  wellerency  阅读(62)  评论(0编辑  收藏  举报