• 动态规划——线性DP


    线性DP入门的三道经典题思路这里就不多说了,直接上代码:

    数字三角形:

    题目链接:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 500+10;
    int n;
    int a[N][N];
    int main()
    {
        memset(a,-0x1f,sizeof(a));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
            {
                scanf("%d",&a[i][j]);
                if(i>1)a[i][j]+=max(a[i-1][j],a[i-1][j-1]);
            }
            
        int maxx=-2e+9;
        for(int i=1;i<=n;i++)maxx=max(maxx,a[n][i]);
        printf("%d
    ",maxx);
        return 0;
    }

    LIS问题:

    题目链接:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int N = 1000+10;
    int n;
    int a[N],f[N];
    
    int main()
    {
        scanf("%d",&n);
        int maxx=a[0]=-2e+9;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            for(int j=0;j<i;j++)
                if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
            maxx=max(maxx,f[i]);
        }
        printf("%d
    ",maxx);
        return 0;
    }

    LCS问题:

    题目链接:

    #include<bits/stdc++.h>
    using namespace std;
    char sa[2010],sb[2010];
    int f[2010][2010];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch>'9'|| ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x*f;
    }
    int main()
    {
        int la=read(),lb=read();
        scanf("%s%s",sa+1,sb+1);
        for(int i=1;i<=la;i++)
            for(int j=1;j<=lb;j++)
            {
                f[i][j]=max(f[i-1][j],f[i][j-1]);
                if(sa[i]==sb[j])f[i][j]=max(f[i][j],f[i-1][j-1]+1);
             } 
        printf("%d
    ",f[la][lb]);
        return 0;
    }

    LIS问题二分算法 

      题目链接:

      这里要讲的是LIS问题二分+贪心算法,可以将时间复杂度从O(n²)降低为O(nlogn)

    [算法思路]

      用数组b存储序列a的最长上升子序列,同时记录b的长度len,并用以下方法维护b数组:
    枚举a[i],若a[i]>b[len],则直接把a[i]接到b数组后面;否则在b数组中查找第一个大于等于a[i]的数并替换之。由于b数组具有单调性,故可以使用二分查找。

    [代码]

    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    const int N=100000+10;
    int a[N],b[N];
    
    int binary_search(int l,int r,int num)
    {
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(b[mid]<num)l=mid+1;
            else r=mid;
        }
        return l;
    }
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x*f; 
    }
    
    int main()
    {
        int n=read(),len=1;
        b[1]=a[1]=read();
        for(int i=2;i<=n;i++)
        {
            if((a[i]=read())>b[len])b[++len]=a[i];
            else b[binary_search(1,len,a[i])]=a[i];
        }
        printf("%d
    ",len);
        return 0;
    }

    编辑距离

      再介绍一道“编辑距离”问题:

      题目链接:

      DP思路:对于两个字符串A和B,我们仍然是维护二维的F数组进行DP。F[i,j]表示到字符串A的i位置和字符串B的j位置为止的最小编辑距离。为了得到F[i,j],我们有六种操作,分别是:在Ai-1后面插入字符Bi,将Bj字符删除;将Ai字符删除,在Bi-1后面插入字符Ai;将Ai改成Bj,将Bj改成Ai(仅限于Ai≠Bj时)。显然,这六种操作中,第一和二,三和四,五和六种操作都是等价的,故可以合并为三种。于是我们便可以得到状态转移方程:

      F[i,j]=min{F[i-1][j]+1,F[i][j-1]+1,F[i-1][j-1](if Ai==Bj),F[i-1][j-1]+1(if Ai!=Bj)}

      边界:F[i][0]=F[0][j]=0;目标:F[la][lb]

      代码如下:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define N 1000+10
    using namespace std;
    int f[15][15];
    char sa[N][15],sb[15];
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch>'9'|| ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x*f;
    }
    
    int main()
    {
        int n=read(),m=read();
        for(int i=1;i<=n;i++)scanf("%s",sa[i]+1); 
        for(int k=1;k<=m;k++)
        {
            scanf("%s",sb+1);
            int num=read(),sum=0;
            for(int q=1;q<=n;q++)
            {
                int la=strlen(sa[q]+1),lb=strlen(sb+1);
                for(int i=0;i<=la;i++)f[i][0]=i;
                for(int i=0;i<=lb;i++)f[0][i]=i;
                for(int i=1;i<=la;i++)
                    for(int j=1;j<=lb;j++)
                    {
                        f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
                        f[i][j]=min(f[i][j],f[i-1][j-1]+1);
                        if(sa[q][i]==sb[j])
                            f[i][j]=min(f[i][j],f[i-1][j-1]);
                    }
                if(f[la][lb]<=num)sum++;
            }
            printf("%d
    ",sum);
        }
        return 0;
    }
  • 相关阅读:
    Java 解惑:Random 种子的作用、含参与不含参构造函数区别
    Linux系统网络性能实例分析
    数据库服务器的性能调优-续
    Spring代理模式及AOP基本术语
    Spring框架总结
    单例模式和多例模式
    jqueryUI小案例
    Ajax讲解
    数据校验和国际化
    文件上传(多文件上传)/下载
  • 原文地址:https://www.cnblogs.com/ninedream/p/11191860.html
Copyright © 2020-2023  润新知