• loj6005 [网络流24题]最长递增子序列


    题意:给你一个序列,求不严格上升lcs长度/最多有几个没有重复元素的lcs/如果x1和xn可以多次出现,求最多有几个lcs?n<=500.

    标程:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<queue>
     5 using namespace std;
     6 const int N=510;
     7 const int inf=0x3f3f3f3f;
     8 queue<int> q;
     9 int cnt=1,dis[N],S,T,x1,xn,a[N],f[N],Head[N],ans,head[N],n,Max,tmp,ans1;
    10 struct node{int to,next,w;}num[N*N*2];
    11 void add(int x,int y,int w)
    12 {num[++cnt].to=y;num[cnt].next=head[x];num[cnt].w=w;head[x]=cnt;
    13 num[++cnt].to=x;num[cnt].next=head[y];num[cnt].w=0;head[y]=cnt;}
    14 void build()
    15 {
    16     for (int i=1;i<=n;i++)
    17       for (int j=i+1;j<=n;j++)
    18         if (a[i]<=a[j]&&f[i]+1==f[j]) add((i==1)?x1:((i==n)?xn:i),j,1);
    19     for (int i=1;i<=n;i++)
    20     {
    21         if (f[i]==1) add(S,i,1);
    22        if (f[i]==Max) add((i==1)?x1:((i==n)?xn:i),T,1);
    23     }
    24     add(1,x1,1);add(n,xn,1);
    25 }
    26 bool bfs()
    27 {
    28     memset(dis,0,sizeof(dis));dis[S]=1;
    29     q.push(S);
    30     while (!q.empty())
    31     {
    32         int now=q.front();q.pop();
    33         for (int i=head[now];i;i=num[i].next)
    34           if (num[i].w&&!dis[num[i].to])
    35             dis[num[i].to]=dis[now]+1,q.push(num[i].to);
    36     }
    37     return dis[T]!=0;
    38 }
    39 int dfs(int x,int mm)
    40 {
    41     int tmp=mm;
    42     if (x==T) return mm;
    43     for (int &i=Head[x];i&&tmp;i=num[i].next)
    44       if (num[i].w&&dis[num[i].to]==dis[x]+1)
    45       {
    46             int t=dfs(num[i].to,min(num[i].w,tmp));
    47             tmp-=t;num[i].w-=t;num[i^1].w+=t;
    48       }
    49     return mm-tmp;
    50 }
    51 void dinic()
    52 {
    53     while (bfs())
    54     {
    55         memcpy(Head,head,sizeof(head));
    56         while (tmp=dfs(S,inf)) ans+=tmp; 
    57     }
    58 }
    59 int main()
    60 {
    61     scanf("%d",&n);S=n+1;T=S+1;x1=T+1;xn=x1+1;
    62     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    63     f[1]=1;
    64     for (int i=2;i<=n;i++)
    65     {
    66         for (int j=1;j<i;j++) 
    67         if (a[i]>=a[j]) f[i]=max(f[i],f[j]);
    68        f[i]++;
    69     }
    70     for (int i=1;i<=n;i++) Max=max(Max,f[i]);
    71     printf("%d
    ",Max);
    72     build();dinic();
    73     printf("%d
    ",ans);ans1=ans;
    74     add(1,x1,inf);add(n,xn,inf);
    75     for (int i=1;i<=n;i++)
    76     {
    77         if (f[i]==1) add(S,i,inf);
    78        if (f[i]==Max) add((i==1)?x1:((i==n)?xn:i),T,inf);
    79     }
    80     dinic();
    81     if (Max==1) printf("%d
    ",ans1);else printf("%d
    ",ans);
    82    return 0;
    83 }

    易错点:1.需要特判lcs=1时询问3的答案和询问2是一样的。不然会错。

    题解:网络流+拆点

    第一问直接dp。

    第二问对于i<j&&a[i]<=a[j]&&f[i]+1==f[j]的(i,j)连容量为1的边,f[i]=1向S连边,f[i]=Max向T连边。跑最大流。

    第三问可以直接在第二问的残图上跑,对于x1和xn点拆点(可以在第二问建图时就拆好),设置点流量为inf。同时对于所有向源汇连的边都设为inf。

  • 相关阅读:
    第七十天 how can I 坚持
    第六十九天 how can I 坚持
    第六十八天 how can I 坚持
    第六十七天 how can I 坚持 (补昨天)
    第六十六天 how can I 坚持··
    第六十五天 how can I 坚持
    第六十四天 how can i 坚持
    第六十三天 how can I 坚持
    MyEclipse10 中的两种FreeMarker插件的安装与配置
    画板社交工具开发分享——HTML5 canvas控件、PHP、社交分享学习(四)
  • 原文地址:https://www.cnblogs.com/Scx117/p/8721432.html
Copyright © 2020-2023  润新知