学习笔记14||DP2

898 数字三角形

给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>

using namespace std;

const int N=510,INF=1e9;
int f[N][N],a[N][N];

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=i;j++) 
          cin>>a[i][j];
     for(int i=1;i<=n;i++)
      for(int j=0;j<=i+1;j++)       
        f[i][j]=-INF;
        f[1][1]=a[1][1];
    for(int i=1;i<=n;i++)
       for(int j=1;j<=i;j++)
           { f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];
            //cout<<f[i][j]<endl;
               
           }
       int res=-INF;
       for(int i=1;i<=n;i++) res=max(res,f[n][i]);
       cout<<res<<endl;
       return 0;
}

895最长上升子序列

DP问题的考虑是从维数小开始考虑。
f[i]所有以第i个数结尾的上升子序列。
以i-1是啥来进行分类。f[i]=f[i-1]+1;
在这里插入图片描述
时间复杂度分析:状态的数量为n,计算的数量也是n,所以时间的复杂度为n2;

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int n,a[N],f[N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        f[i]=1;//只有a[i]一个数
        for(int j=1;j<i;j++)
          if(a[j]<a[i]) 
            f[i]=max(f[i],f[j]+1);
          
    }
    int res=0;
    for(int i=1;i<=n;i++) res=max(res,f[i]);
    printf("%d",res);
    return 0;
}

求方案,就是把转移的过程记录下来,然后进行输出。

897 最长公共子序列

1、状态表示:

  • 集合:f[i,j]第一个序列的前i个字母以及,第二个序列的第j个字母的最长公共子序列
  • 属性:最大
    2、状态计算:a[i],b[j]是否在集合当中。一共有四种情况,不重不漏。
    在这里插入图片描述
#include<iostream>
#include<algorithm>

using namespace std;

const int N=1010;

int n,m;
int f[N][N];
char a[N],b[N];

int main(){
    scanf("%d%d",&n,&m);
    scanf("%s%s",a+1,b+1);
    
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
      {
          f[i][j]=max(f[i-1][j],f[i][j-1]);
          if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
      }
      printf("%d\n",f[n][m]);
      return 0;
}

282 石子合并

设有N堆石子排成一排,其编号为1,2,3,…,N。
每堆石子有一定的质量,可以用一个整数来描述,现在要将这N堆石子合并成为一堆。
每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。
区间DP问题
1、状态表示

  • 集合:所有将i堆石子到第j堆石子合并成一堆石子的合并方式。
  • 属性:min
    2、状态计算:以最后一次分界线的位置进行分类,分成多类。
    在这里插入图片描述
    f[i,j]=min{f[i,k]+f[k+1,j]+s[j]-s[i-1]};
#include<iostream>
#include<algorithm>

using namespace std;

const int N=310;

int n;
int s[N];
int f[N][N];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    for(int i=1;i<=n;i++) s[i]+=s[i-1];
    
    for(int len=2;len<=n;len++)
      for(int i=1;i+len-1<=n;i++)//起点
      {
          int l=i,r=i+len-1;
          f[l][r]=1e8;
          for(int k=l;k<r;k++)
            f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
      }

    printf("%d",f[1][n]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值