洛谷 P1880 [NOI1995]石子合并(区间dp,断环为链)

传送门


解题思路

区间dp:一般dp[i][j]表示区间i...j的答案,这个答案可以从某个或某些小区间转移而来。

大部分题的解法就是先枚举做外层循环len,表示区间长度,然后枚举区间左端点i,然后计算出右端点j,然后枚举i到j中的所有断点,根据dp[i][k],dp[k+1][j]计算出dp[i][j]。

这个题因为是一周,是一个环形,所以我们先进行断环为链的操作。

AC代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=205;
 6 int n,a[maxn],dp1[maxn][maxn],dp2[maxn][maxn],s[maxn];
 7 int main()
 8 {
 9     cin>>n;
10     for(int i=1;i<=n;i++){
11         cin>>a[i];
12     }
13     for(int i=1;i<=n-1;i++){
14         a[n+i]=a[i];
15     }
16     for(int i=1;i<=2*n-1;i++){
17         s[i]=s[i-1]+a[i];
18     }
19     for(int len=2;len<=n;len++){
20         for(int i=1;i<=2*n-1;i++){
21             int j=i+len-1;
22             if(j>2*n-1) break;
23             dp2[i][j]=0x3f3f3f3f;
24             for(int k=i;k<j;k++){
25                 dp1[i][j]=max(dp1[i][j],dp1[i][k]+dp1[k+1][j]);
26                 dp2[i][j]=min(dp2[i][j],dp2[i][k]+dp2[k+1][j]);
27             }
28             dp1[i][j]+=s[j]-s[i-1];
29             dp2[i][j]+=s[j]-s[i-1];
30         }
31     }
32     int ansmax=0,ansmin=0x3f3f3f3f;
33     for(int i=1;i<=n;i++){
34         ansmax=max(ansmax,dp1[i][i+n-1]);
35         ansmin=min(ansmin,dp2[i][i+n-1]);
36     }
37     cout<<ansmin<<endl<<ansmax<<endl;
38     return 0;
39 }

 //NOI1995 Day?T2

posted @ 2020-02-22 18:35  尹昱钦  阅读(174)  评论(0编辑  收藏  举报