算法基础课DP总结

首先借助大佬的图引入y总的闫氏DP:

 

 

 

 总结的很全面,也很详细.

那么基础课的DP目录:

1、背包问题:

(1)01背包

(2)完全背包

(3)多重背包问题

(4)分组背包问题

2、线性DP

(1)数字三角形

(2)最长上升子序列

(3)字符串问题

3、区间DP   282. 石子合并 - AcWing题库

4、计数类DP  900. 整数划分 - AcWing题库

5、数位统计DP 338. 计数问题 - AcWing题库

6、状态压缩DP  291. 蒙德里安的梦想 - AcWing题库  91. 最短Hamilton路径 - AcWing题库

7、树形DP 285. 没有上司的舞会 - AcWing题库

8、记忆化搜索 901. 滑雪 - AcWing题库

 

背包类模板:

01背包:( 时间复杂度O(n^m) )

for(int i = 0; i < n ; i++)
{
     for(int j=m;j>=v[i];j--)
     {
          f[j]=max(f[j],f[j-v[i]]+w[i]);
     }
}

 

完全背包:

朴素版: ( 时间复杂度O(n^m^m) )

for(int i = 0 ; i<=m ;j++)
{
       for(int j = 0 ; j<=m ;j++)
      {
            for(int k = 0; k * v [ i ] <= j; k++)
            f[i][j]= max(f[i][j],f[i-1][ j  - k * v [i] ]+ k * w [i] );
      }
}

 

优化版本:( 时间复杂度O(n^m) )

for(int i=1;i<=n;i++)
{
for(int j = v [i]; j <= m; j++) f[j]= max( f[j], f[ j - v[i] ]+ w[i]); }

 

 

多重背包问题I:( 时间复杂度O(n^m^m) )

for(int i = 1; i<=n; i++)
{
     int v,w,s;
     cin>>v>>w>>s;//v是重量,w是价值,s是限制数量
     for(int j = m; j>=0 ; j--)
            for(int k=1 ; k<=s && k*v<=j ; k++)
            f[j] = max( f[j] , f[ j-k*v ] + k*w );
}

 

多重背包问题II:( 时间复杂度O(n^m) )

vector<goods> S;
for(int i=0;i<n;i++)
{
      int v,w,s;
      cin>>v>>w>>s;
      for(int j=1;j<=s;j*=2)
      {
          s-=j;
          S.push_back({j*v,j*w});
      }
      if(s>0)S.push_back({s*v,s*w});
}
for(auto g:S)
{
     for(int j=m;j>=g.v;j--)
     {
          f[j]=max(f[j],f[j-g.v]+g.w);
     }
}

 

分组背包问题:( 时间复杂度O(n^m) )

 

for(int i=0;i<n;i++)
{
     int l;
     cin>>l;
     for(int j=0;j<l;j++)cin>>v[j]>>w[j];
     for(int j=m;j>=0;j--)
         for(int k=0;k<l;k++)
            if(v[k]<=j)
               f[j]=max(f[j],f[j-v[k]]+w[k]);
}

 

 

 

数字三角形:( 时间复杂度O(n^2) )

 

for(int i=1;i<=n;i++)  f[n][i]=w[n][i];//初始化
for
(int i=n-1;i;i--) for(int j=1;j<=i;j++) f[i][j]=max(f[i+1][j]+w[i][j],f[i+1][j+1]+w[i][j]);

 

 

最长上升子序列:( 时间复杂度O(n^2) )

for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
        {
            if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
        }
    }

 

最长上升子序列:(二分法)( 时间复杂度O(n*lnn) )

for(int i=0;i<n;i++)
    {
        int l=0,r=len;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(q[mid]<a[i])l=mid;
            else r=mid-1;
        }
        len=max(len,r+1);
        q[r+1]=a[i];
    }

 

最长公共子序列:

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);
    }
}

 

字符串编辑问题:

 

for(int i=0;i<=n;i++)f[i][0]=i;
    for(int i=0;i<=m;i++)f[0][i]=i;
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
            if(a[i]==b[j]) f[i][j]=min(f[i][j],f[i-1][j-1]);
            else f[i][j]=min(f[i][j],f[i-1][j-1]+1);
        }
    }

 

 

 

END!!!

 

posted @ 2022-04-04 10:59  秦末  阅读(85)  评论(0)    收藏  举报
1 博文导航目录