zoukankan      html  css  js  c++  java
  • 【网络流24题】最长递增子序列

    Description

    给定正整数序列x1,..., xn。
    (1)计算其最长递增子序列的长度s。
    (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
    (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
    设计有效算法完成(1)(2)(3)提出的计算任务

    Input

    第1 行有1个正整数n(n<=500),表示给定序列的长度。
    接下来的1 行有n个正整数x1,..., xn。

    Output

    第1 行是最长递增子序列的长度s。
    第2行是可取出的长度为s 的递增子序列个数。
    第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。

    Sample Input

    4
    3 6 2 5

    Sample Output

    2
    2
    3

    Hint

    Source

    网络流
    最多不相交路径,网络最大流

    思路{

      第一问DP求解

      第二问,第三问网络流即可{

        虚拟源汇点,从sf[i]=1的连容量为1,中间转移的容量为1f[i]max的连向汇点,容量为1,最大流即可。

        虚拟源汇点,从sf[i]=1的连容量为INF,中间转移的容量为1f[i]max的连向汇点,容量为INF,最大流即可。

        记(wei)得(suo)特判一下

      }

    }

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<ctime>
    #include<cmath>
    #include<map>
    #include<set>
    #define MAXX 502
    #define MAXM 502*502+1001
    #define INF 9999999
    using namespace std;
    
    struct se{
      int nxt,to,c;
    }e[MAXM*4];
    
    int n,m,a[MAXX+1],f[MAXX+1],tot,head[MAXX+1],deep[MAXX+1],all;
     
    void add(int from,int to,int w){
      e[tot].nxt=head[from];
      e[tot].to=to;
      e[tot].c=w;
      head[from]=tot++;
    }
    void ADD(int from,int to,int w){
      add(from,to,w);
      add(to,from,0);
    }
    void DP(){
      f[1]=1;
      for(int i=2;i<=n;++i){
        for(int j=i-1;j;j--){
          if(f[j]>f[i]&&a[j]<=a[i])
        f[i]=f[j];
        }f[i]++;
      }for(int i=1;i<=n;++i)all=max(all,f[i]);
      printf("%d
    ",all);
    }
    bool BFS(int s,int t){
      queue<int>que;
      while(!que.empty())que.pop();
      for(int i=1;i<=n+2;++i)deep[i]=0;
      que.push(s),deep[s]=1;
      while(!que.empty()){
        int u=que.front();
        for(int i=head[u];i!=-1;i=e[i].nxt)if(!deep[e[i].to]&&e[i].c){
        int v=e[i].to;
        deep[v]=deep[u]+1;
        que.push(v);
        if(v==t)return 1;
          }
        que.pop();
      }return 0;
    }
    int dinic(int s,int t,int T){
      if(s==t)return T;int tag=0;
      for(int i=head[s];i!=-1;i=e[i].nxt)if(e[i].c&&deep[e[i].to]==deep[s]+1){
          int d=dinic(e[i].to,t,min(T,e[i].c));
          e[i].c-=d,e[i^1].c+=d;tag+=d;
          if(tag==T)return tag;
        }return tag;
    }
    void flow1(){
      for(int i=1;i<=n;++i)if(f[i]==1)ADD(0,i,1);
      for(int j=2;j<=n;++j){
        if(f[j]==all)ADD(j,n+1,1);
        for(int i=1;i<j;++i)
          if((f[i]+1==f[j])&&a[i]<=a[j])
        ADD(i,j,1);
      }
      int ans=0;
      while(BFS(0,n+1))ans+=dinic(0,n+1,INF);
      if(all!=1)
      printf("%d
    ",ans);
      else cout<<ans+1<<'
    ';
    }
    void flow2(){
      memset(e,0,sizeof(e));tot=0;
      memset(head,-1,sizeof(head));
      for(int i=1;i<=n;++i)if(f[i]==1)ADD(0,i,INF);
      for(int j=2;j<=n;++j){
        if(f[j]==all)ADD(j,n+1,INF);
        for(int i=1;i<j;++i)
          if((f[i]+1==f[j])&&a[i]<=a[j])
        ADD(i,j,1);
      }
      int ans=0;
      while(BFS(0,n+1))ans+=dinic(0,n+1,INF);
      printf("%d
    ",ans);
    }
    int main(){
      memset(head,-1,sizeof(head));
      scanf("%d",&n);
      for(int i=1;i<=n;++i)scanf("%d",&a[i]);
      DP();
      if(all!=1)flow1(),flow2();
      if(all==1)flow1(),flow1();
      return 0;
    }
  • 相关阅读:
    SDOI2008]仪仗队
    洛谷P1414 又是毕业季II
    P3865 【模板】ST表
    [HAOI2007]理想的正方形
    noip 2011 选择客栈
    [AHOI2009]中国象棋
    洛谷P3387 【模板】缩点
    [SCOI2005]最大子矩阵
    [CQOI2009]叶子的染色
    LibreOJ #116. 有源汇有上下界最大流
  • 原文地址:https://www.cnblogs.com/zzmmm/p/6658585.html
Copyright © 2011-2022 走看看