洛谷 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