zoukankan      html  css  js  c++  java
  • 『一本通』区间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(画图理解)

    分离与合体

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,a[305],f[305][305],h[305][305];
     4 queue<int>ql,qr;
     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 void print() {
    13     ql.push(1); qr.push(n);
    14     while(!ql.empty()) {
    15         int l=ql.front(),r=qr.front(); ql.pop();qr.pop();
    16         printf("%d ",h[l][r]);
    17         if(l!=h[l][r]) {ql.push(l); qr.push(h[l][r]);}
    18         if(h[l][r]+1!=r) {ql.push(h[l][r]+1); qr.push(r);} 
    19     }
    20 }
    21 
    22 int main() {
    23     n=read();
    24     for(int i=1;i<=n;i++) a[i]=read();
    25     for(int i=2;i<=n;i++)
    26      for(int l=1;l+i-1<=n;l++) {
    27          int r=l+i-1;
    28          for(int k=l;k<r;k++)
    29           if(f[l][r]<f[l][k]+f[k+1][r]+(a[l]+a[r])*a[k]) {
    30               f[l][r]=f[l][k]+f[k+1][r]+(a[l]+a[r])*a[k];
    31               h[l][r]=k;
    32           }
    33      }
    34     printf("%d
    ",f[1][n]);
    35     print();
    36 }
    37 /*
    38 区间DP
    39 f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+(a[l]+a[r])*a[k]) <如题意>
    40 用h[l][r]记录[L...R]区间合并价值最大的分离区域编号
    41 利用队列依次输出分离区域编号(阶段从前到后,区域从左到右)
    42 */

    完结撒花 (2018.12.20)

  • 相关阅读:
    【转】BT5汉化步骤
    创建MySql用户并给用户授权,设置mariadb默认编码,修改mariadb数据存储目录datadir
    《Hadoop实战》陆嘉恒著读书笔记
    org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException: The content of elements must consi
    js获取两个日期之间间隔的天数。兼容IE6、7、8、9,Firefox,Chrome
    mac下下载安装Android Studio教程
    Android Studio下载安装教程及开发环境搭建
    【eoe资源】如何让Android ListView的平滑滚动
    安装Android Studio遇到中文乱码的解决方法
    最新android studio注意事项打不开等问题6种解决方法
  • 原文地址:https://www.cnblogs.com/qq8260573/p/10145477.html
Copyright © 2011-2022 走看看