• 线性DP+树形DP


    线性DP

    1. 最长上升(不下降)子序列

    O(n^2)的基础算法,如果是不下降只用把f[i]<f[j]改成f[i]<=f[j]

    方程:f[i]=max(f[j]+1) j∈i+1~n

    ps:每个位置的初始长度都是1!!!!

    //最长上升序列
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
     
    using namespace std;
    int n,a[5005],f[5005];
     
    int main()
    {
        ios::sync_with_stdio(false);
         
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            f[i]=1;
        }
    //  f[n]=1;每个位置都是1
        for(int i=n-1;i>=1;i--)
        {
            for(int j=i+1;j<=n;j++)
            {
                if(a[i]<a[j])
                    f[i]=max(f[i],f[j]+1);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=max(ans,f[i]);
        }
        cout<<ans;
     
        return 0;
    }
    

    O(n*logn)的进阶算法,主要思想是贪心和二分
    导弹拦截

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    int a[100005],p,f[100005],k=0;
    
    int main()
    {
    	
    	while(cin>>a[p])
    	{ 
    		p++;
    	}
    	f[0]=a[0];
    	for(int i=1;i<p;i++)
    	{
    		if(a[i]<=f[k])
    		{
    			f[++k]=a[i];
    		}
    		else
    		{
    			int x=upper_bound(f,f+k,a[i],greater<int>())-f;
    			f[x]=a[i];
    		}
    	}	
    	cout<<k+1<<endl;
    	k=0;
    	memset(f,0,sizeof(f));
    	f[0]=a[0];
    	for(int i=1;i<p;i++)
    	{
    		if(a[i]>f[k])
    		{
    			f[++k]=a[i];
    		}
    		else
    		{
    			int x=lower_bound(f,f+k,a[i])-f;
    			f[x]=a[i];
    		}
    	}	
    	cout<<k+1<<endl;
    	
    	return 0;	
    } 
    

    主要是贪心思想,对于每个a[i],如果a[i]>f[end],a[i]就接在f[end];

    反之,替换掉f数组中大于a[i]的最小的(upper_bound(f.begin,f.end,a[i]))

    不好严格证明,如下为示例:

    样例:

    14
    13 7 9 16 38 24 37 18 4 19 21 22 63 15
    

    过程:

    13
    7
    7 9
    7 9 16 38
    7 9 16 24
    7 9 16 18
    7 9 16 18 19
    7 9 16 18 19 21 22 63
    7 9 15 18 19 21 22 63
    

    2. 最长公共子序列(LCS)

    给定一个序列X=<x1,x2,x3,x4...,xm>,另一个序列Z=<z1,z2,z3,z4...,zk>,若存在一个严格递增的X的下标序列<i1,i2,i3,...,ik>对所有的1,2,3,...,k,都满足x(ik)=zk,则称Z是X的子序列

    比如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>的子序列

    方程:f(i,j)={f[i-1,j-1](a[i]=a[j]),max(f[i-1][j],f[i][j-1])(a[i]≠a[j]}

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
     
    using namespace std;
    char a[205],b[205];
    int f[205][205];
     
    int main()
    {
    //  ios::sync_with_stdio(false);
     
        scanf("%s",a+1);
        scanf("%s",b+1);
        strlen()
        int lena=strlen(a+1),lenb=strlen(b+1);//从下标1开始计算长度 size t cdecl strlen (const char  Str)
        for(int i=1;i<=lena;i++)
        {
            for(int j=1;j<=lenb;j++)
            {
                if(a[i]==b[j])
                    f[i][j]=f[i-1][j-1]+1;
                else
                    f[i][j]=max(f[i-1][j],f[i][j-1]);
            }
        }
        cout<<f[lena][lenb];
     
        return 0;
    }
    

    最经典的是这个图

    img

  • 相关阅读:
    HbuildeX项目打包
    百度地图(vue)
    压缩图片
    安卓移动端唤起拨号与邮箱
    上传图片 原生或vant
    git从零开始
    HbuilderX,监视物理按键
    gitlab备份and恢复数据
    ⑨.kubernetes 之ingress
    ⑧.kubernetes pod调度
  • 原文地址:https://www.cnblogs.com/huaruoji/p/12947605.html
Copyright © 2020-2023  润新知