『一本通』区间DP

Posted qq8260573

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『一本通』区间DP相关的知识,希望对你有一定的参考价值。

石子合并

 1 #include<bits/stdc++.h>
 2 #define INF 0x3f3f3f3f
 3 using namespace std;
 4 int n,sm[505][505],bg[505][505],sum[505];
 5 inline int read() {
 6     int x=0,f=1; char c=getchar();
 7     while(c<0||c>9) {if(c==-)f=-1; c=getchar();}
 8     while(c>=0&&c<=9) x=(x<<3)+(x<<1)+c-0,c=getchar();
 9     return x*f;
10 }
11 
12 int main() {
13     n=read();
14     for(int i=1;i<=n;i++) sum[i]=read(),sum[i+n]=sum[i];
15     memset(sm,INF,sizeof(sm));
16     for(int i=1;i<=2*n;i++) sm[i][i]=0,sum[i]+=sum[i-1];
17     for(int i=2;i<=n;i++)
18      for(int l=1;l+i-1<=2*n;l++) {
19          int r=l+i-1;
20          for(int k=l;k<r;k++) {
21              sm[l][r]=min(sm[l][r],sm[l][k]+sm[k+1][r]);
22              bg[l][r]=max(bg[l][r],bg[l][k]+bg[k+1][r]);
23          } 
24          sm[l][r]+=sum[r]-sum[l-1];
25          bg[l][r]+=sum[r]-sum[l-1]; 
26      }
27     int minn=INF,maxx=0;
28     for(int i=1;i<=n;i++) {
29         maxx=max(maxx,bg[i][i+n-1]);
30         minn=min(minn,sm[i][i+n-1]);
31     }
32     printf("%d
%d",minn,maxx);
33 }
34 /*
35 区间DP (环形处理+前缀和) 
36 sm[l][r]为合并 l~r 堆石子的得分总和最小值 
37 bg[l][r]为合并 l~r 堆石子的得分总和最大值
38 枚举合并断点 k 
39 得 sm/bg[l][r]=min/max(sm/bg[l][r],sm/bg[l][k]+sm/bg[k+1][r])
40 最后加上这次合并获得的得分 sum[r]-sum[l-1]
41 */

 

能量项链

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,f[1005][1005],a[1005];
 4 inline int read() {
 5     int x=0,f=1; char c=getchar();
 6     while(c<0||c>9) {if(c==-)f=-1; c=getchar();}
 7     while(c>=0&&c<=9) x=(x<<3)+(x<<1)+c-0,c=getchar();
 8     return x*f;
 9 }
10 
11 int main() {
12     n=read();
13     for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i];
14     for(int i=3;i<=n+1;i++) 
15      for(int l=1;l+i-1<=2*n;l++) {
16          int r=l+i-1;
17          for(int k=l+1;k<r;k++)
18           f[l][r]=max(f[l][r],f[l][k]+f[k][r]+a[l]*a[r]*a[k]);
19      }
20     int ans=0;
21     for(int i=1;i<=n;i++) ans=max(ans,f[i][i+n]);
22     printf("%d",ans);
23 }
24 /*
25 区间DP
26 f[i][j]:将 i~j-1 的珠子聚合所能释放的最大能量
27 注意循环的边界。
28 */ 

 

矩阵取数

 1 #include<bits/stdc++.h>
 2 #define int __int128 //拯救你的高精度 
 3 using namespace std;
 4 int n,m,ans,a[105],f[105][105];
 5 inline int read() {
 6     int x=0,f=1; char c=getchar();
 7     while(c<0||c>9) {if(c==-)f=-1; c=getchar();}
 8     while(c>=0&&c<=9) x=(x<<3)+(x<<1)+c-0,c=getchar();
 9     return x*f;
10 }
11 void write(int x) {
12     if(x>9) write(x/10);
13     putchar(x%10+0);
14 }
15 
16 main() {
17     n=read(),m=read();
18     for(int k=1;k<=n;k++) {
19         for(int i=1;i<=m;i++) a[i]=read()*2,f[i][i]=a[i];
20         for(int i=2;i<=m;i++)
21          for(int l=1;l+i-1<=m;l++) {
22              int r=l+i-1;
23              f[l][r]=max(a[l]+f[l+1][r]*2,a[r]+f[l][r-1]*2);
24          }
25         ans+=f[1][m];
26     }
27     write(ans);
28 }
29 /*
30 区间DP
31 每一行取数不会影响到其它行,只要保证每一行得分最大即可(最优子结构)
32 设f[i][j]表示取区间[i][j]的最大得分。
33 转移方程:f[l][r]=max(a[l]+f[l+1][r]*2,a[r]+f[l][r-1]*2) 
34 细节(输入时将a[i]*2)
35 */ 

 

括号配对

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char a[105];
 4 int len,f[105][105];
 5 int main() {
 6     scanf("%s",a+1); len=strlen(a+1);
 7     for(int l=len;l>0;l--)
 8      for(int r=l+1;r<=len;r++) {
 9         if((a[l]==(&&a[r]==))||(a[l]==[&&a[r]==])) f[l][r]=2+f[l+1][r-1];
10         for(int k=l;k<r;k++) f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);
11      }
12     printf("%d",len-f[1][len]);
13 }
14 /*
15 区间DP
16 题目要求添加的括号数,只需将括号总数减去已匹配的括号数(求出未匹配的括号数) 
17 未匹配的括号数=需添加的括号数
18 所以我们求最多能匹配多少个括号(区间DP:判断匹配情况+枚举断点)
19 注意:第一层循环(枚举L)应为LEN~1(方程式要从后面的情况转移) 
20 */ 

 

凸多边形的划分

 1 #include<bits/stdc++.h>
 2 #define int __int128 
 3 using namespace std;
 4 int n,a[55],f[55][55];
 5 void print(int x) {
 6     if(x<0) putchar(-),x=-x;
 7     if(x>9) print(x/10);
 8     putchar(x%10+0);
 9 }
10 
11 main() {
12     scanf("%d",&n);
13     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
14     for(int i=3;i<=n;i++)
15      for(int l=1;l+i-1<=n;l++) {
16         int r=l+i-1; f[l][r]=1e30;
17         for(int k=l+1;k<r;k++)
18          f[l][r]=min(f[l][r],f[l][k]+f[k][r]+a[l]*a[r]*a[k]);
19      }
20     print(f[1][n]);
21 }
22 //区间DP(画图理解)

 

以上是关于『一本通』区间DP的主要内容,如果未能解决你的问题,请参考以下文章

「一本通 5.1 练习 2」分离与合体 题解

loj10147. 「一本通 5.1 例 1」石子合并

loj10150. 「一本通 5.1 练习 1」括号配对

信息学奥赛一本通 5.2 树形动态规划

一本通1423 种树

「一本通 1.1 例 1」活动安排