• 序列型动规模板


    最长上升子序列(lis)


     1.O(n^2)

     1 #include<cstdio>
     2 #include<algorithm>
     3 using std :: max;
     4 
     5 const int maxn=100005;
     6 int a[maxn],dp[maxn],pre[maxn];
     7 int n;
     8 
     9 void outit(int now)//输出lis 
    10 {
    11     if(pre[now]) outit(pre[now]);
    12     printf("%d ",a[now]);
    13 }
    14 
    15 void solve()
    16 {
    17     for(int i=1;i<=n;i++)
    18     {
    19         dp[i]=1;pre[i]=0;
    20         for(int j=1;j<i;j++)
    21         {
    22             if(a[j]<a[i]&&dp[j]+1>dp[i])
    23             {
    24                 dp[i]=dp[j]+1;
    25                 pre[i]=j;
    26             }
    27         }
    28     }
    29     int ans=0, last;
    30     for(int i=1;i<=n;i++)
    31     {
    32         if(dp[i]>ans)
    33         {
    34             ans=dp[i];
    35             last=i;
    36         }
    37     }
    38     printf("%d
    ",ans);
    39     outit(last);
    40 }
    41 
    42 void init()
    43 {
    44     scanf("%d",&n);
    45     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    46 }
    47 
    48 int main()
    49 {
    50     freopen("lis.in","r",stdin);
    51     freopen("lis.out","w",stdout);
    52     init();
    53     solve();
    54     fclose(stdin);
    55     fclose(stdout);
    56     return 0;
    57 }
    View Code

    2.O(nlogn)

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 const int maxn=10005,INF=0x7fffffff;
     5 struct node
     6 {
     7     int x,num;
     8     node(){}
     9     node(int a,int b) : x(a), num(b) {}
    10     bool operator < (const node &a) const { return x>a.x; }
    11 }dp[maxn];
    12 int a[maxn],pre[maxn];
    13 int n;
    14 
    15 int bsearch(int l,int r,int v)
    16 {
    17     while(l<r)
    18     {
    19         int m=l+(r-l)/2;
    20         if(dp[m].x>=v) r=m;
    21         else l=m+1;
    22     }
    23     return l;
    24 }
    25     
    26 void outit(int now)//输出lis 
    27 {
    28     if(pre[now]) outit(pre[now]);
    29     printf("%d ",a[now]);
    30 }
    31 
    32 void solve()
    33 {
    34     for(int i=1;i<=n+1;i++) dp[i].x=INF;
    35     for(int i=1;i<=n;i++)
    36     {
    37         int idx=bsearch(1,n,a[i]);
    38         dp[idx].x=a[i];
    39         dp[idx].num=i;
    40         pre[i]=dp[idx-1].num;
    41     }
    42     int ans=bsearch(1,n+1,INF)-1;
    43     printf("%d
    ",ans);
    44     outit(dp[ans].num);
    45 }
    46 
    47 void init()
    48 {
    49     scanf("%d",&n);
    50     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    51 }
    52 
    53 int main()
    54 {
    55     freopen("lis.in","r",stdin);
    56     freopen("lis.out","w",stdout);
    57     init();
    58     solve();
    59     fclose(stdin);
    60     fclose(stdout);
    61     return 0;
    62 }
    View Code

    最长公共子序列(lcs)


    O(n^2).暂时没有输出lcs的部分.

     1 #include<cstdio>
     2 #include<algorithm>
     3 using std :: max;
     4 
     5 const int maxn=10005;
     6 int n,m;
     7 int a[maxn],b[maxn];
     8 int dp[maxn][maxn];
     9 
    10 void solve()
    11 {
    12     for(int i=1;i<=n;i++)
    13     {
    14         for(int j=1;j<=m;j++)
    15         {
    16             if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
    17             else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    18         }
    19     }
    20     printf("%d
    ",dp[n][m]);
    21 }
    22 
    23 void init()
    24 {
    25     scanf("%d%d",&n,&m);
    26     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    27     for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    28 }
    29 
    30 int main()
    31 {
    32     freopen("lcs.in","r",stdin);
    33     freopen("lcs.out","w",stdout);
    34     init();
    35     solve();
    36     fclose(stdin);
    37     fclose(stdout);
    38     return 0;
    39 }
    View Code

    最长公共上升子序列(lcis)


    状态转移方程:

    a[i]==b[j]时:dp[j]=max(dp[k]+1) (1<=k<j&&b[k]<b[j])

    dp[j]表示以b[j]结尾的lcis,a串最为外层循环,当a串到a[i]位置,b串到b[j]位置时,dp[j]存储的是a串在a[i-1]位置,b串在b[j]位置时的最优值.此时判断a[i]是否等于b[j]:

    1.a[i]!=b[j],现在的最优值等于a在a[i-1]位置时的最优值,即dp[j]不变. 

    2.a[i]==b[j],dp[j]=max(dp[k]+1) (1<=k<j&&b[k]<b[j]).

    对于这个k,如果到了a[i]==b[j]时再返回从b[1]~b[j-1]找就O(n^3)了,所以在到达b[j]之前就记录最优的dp[k]与k.a[i]==b[j]时,b[k]<b[j]=a[i],

    所以在a[i]的循环中,对于b串当前的b[j]位置,如果b[j]<a[i]&&maxk(最优dp[k])<dp[j],那么maxk=dp[j],k=j.

    ps.因为要输出lcis,所以ans不记录最优dp[j],而是最优dp[j]对应的j.

     1 #include<cstdio>
     2 
     3 const int maxn=10005;
     4 int n,m;
     5 int a[maxn],b[maxn],dp[maxn],pre[maxn];
     6 
     7 void print_lcis(int now)//输出lcis 
     8 {
     9     if(pre[now]) print_lcis(pre[now]);
    10     printf("%d ",b[now]);
    11 }
    12 
    13 void solve()
    14 {
    15     int ans;//lcis在b中的末位置 
    16     for(int i=1;i<=n;i++)
    17     {
    18         int maxk=0,k=0;//到当前j为止满足1<=k<j且b[k]<b[j]的dp[k]的值以及k 
    19         for(int j=1;j<=m;j++)
    20         {
    21             if(b[j]<a[i]&&dp[j]>maxk) { maxk=dp[j]; k=j; }
    22             if(b[j]==a[i])
    23             {
    24                 dp[j]=maxk+1;
    25                 pre[j]=k;
    26                 if(dp[j]>dp[ans]) ans=j;
    27             }
    28         }
    29     }
    30     printf("%d
    ",dp[ans]);
    31     print_lcis(ans);
    32 }
    33 
    34 void init()
    35 {
    36     scanf("%d%d",&n,&m);
    37     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    38     for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    39 }
    40 
    41 int main()
    42 {
    43     freopen("lcis.in","r",stdin);
    44     freopen("lcis.out","w",stdout);
    45     init();
    46     solve();
    47     fclose(stdin);
    48     fclose(stdout);
    49     return 0;
    50 }
    View Code
  • 相关阅读:
    点击listview 的列头对其item进行自动排序
    将选择的图片显示在listview中,并显示filename,path和type
    【翻译】8 个可以节省时间的 C# 开发相关工具
    【原创】关于乘法运算的新思路
    【翻译】为什么我们要用抽象类?
    【翻译】如何使用 C# 的 BackgroundWorker
    【汉化】DevExpress插件中RichEdit控件的自定义汉化方法
    关于C#日期格式化问题
    C#获取(大陆)身份证基本信息的算法
    C#关于精确年龄的算法(精确到天)
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5422006.html
Copyright © 2020-2023  润新知