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

    Description

    给定正整数序列$x_1,x_2,...,x_n$.

    $1.$计算其最长递增子序列的长度$L$。

    $2.$计算从给定的序列中最多可取出多少个长度为$L$的递增子序列。

    $3.$如果允许在取出的序列中多次使用$x_1,x_n$,则从给定序列中最多可取出多少个长度为$L$的递增子序列。

    Input

    第$1$行有$1$个正整数$n$,表示给定序列的长度。

    接下来的$1$行有$n$个正整数$x_1,x_2,...,x_n$。

    Output

    第$1$行是最长递增子序列的长度$L$。

    第$2$行是可取出的长度为$L$的递增子序列个数。

    第$3$行是允许在取出的序列中多次使用$x_1,x_n$时可取出的长度为$L$的递增子序列个数。

    Sample Input

    4
    3 6 2 5

    Sample Output

    2
    2
    3

    HINT

    $n<500$

    Solution

    • 第一问:

    最简单的$LIS$的$DP$.

    • 第二问:

    将每个数$a_i$进行拆点:$x_i,y_i$,中间连一条边限制其流量(即使用次数).

    从$x_i$向$y_i$连一条容量为$1$的有向边.

    如果$f[i]=L$,从$s$向$x_i$连一条容量为$1$的有向边.

    如果$f[i]=1$,从$y_i$向$t$连一条容量为$1$的有向边.

    如果$i<j,a_i<a_j,f[i]+1=f[j]$,从$y_j$向$x_i$连一条容量为$1$的有向边.

    求最大流.

    • 第三问:

    将$(x_1,y_1),(x_n,y_n),(x_1,t),(s,x_n)$的值改成$+infty$.

    求最大流.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 500
    #define M 500000
    using namespace std;
    struct graph{
        int nxt,to,f;
    }e[M];
    int a[N],f[N],g[N<<1],dep[N<<1],n,m,s,t,cnt=1;
    queue<int> q;
    inline void addedge(int x,int y,int f){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    }
    inline void adde(int x,int y,int f){
        addedge(x,y,f);addedge(y,x,0);
    }
    inline bool bfs(int u){
        memset(dep,0,sizeof(dep));
        q.push(u);dep[u]=1;
        while(!q.empty()){
            u=q.front();q.pop();
            for(int i=g[u];i;i=e[i].nxt)
                if(e[i].f>0&&!dep[e[i].to]){
                    q.push(e[i].to);
                    dep[e[i].to]=dep[u]+1;
                }
        }
        return dep[t];
    }
    inline int dfs(int u,int f){
        int ret=0;
        if(u==t) return f;
        for(int i=g[u],d;i&&f;i=e[i].nxt)
            if(e[i].f>0&&dep[e[i].to]>dep[u]){
                d=dfs(e[i].to,min(f,e[i].f));
                ret+=d;f-=d;e[i].f-=d;e[i^1].f+=d;
            }
        return ret;
    }
    inline int dinic(){
        int ret=0;
        while(true){
            if(!bfs(s)) return ret;
            ret+=dfs(s,M);
        }
    }
    inline void Aireen(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;++i){
            f[i]=1;
            for(int j=1;j<i;++j)
                if(a[j]<a[i])
                    f[i]=max(f[i],f[j]+1);
            m=max(m,f[i]);
        }
        printf("%d
    ",m);
        s=(n<<1)+1;t=s+1;
        for(int i=1;i<=n;++i){
            adde(i,i+n,1);
            if(f[i]==1) adde(i+n,t,1);
            if(f[i]==m) adde(s,i,1);
            for(int j=1;j<i;++j)
                if(a[j]<a[i]&&f[j]+1==f[i])
                    adde(i+n,j,1);
        }
        printf("%d
    ",dinic());
        cnt=1;memset(g,0,sizeof(g));
        for(int i=1,c,d,k;i<=n;++i){
            c=d=k=1;
            if(i==1) c=k=M;
            if(i==n) d=k=M;
            adde(i,i+n,k);
            if(f[i]==1) adde(i+n,t,c);
            if(f[i]==m) adde(s,i,d);
            for(int j=1;j<i;++j)
                if(a[j]<a[i]&&f[j]+1==f[i])
                    adde(i+n,j,1);
        }
        printf("%d
    ",dinic());
    }
    int main(){
        freopen("alis.in","r",stdin);
        freopen("alis.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Android集成科大讯飞SDK语音听写及语音合成功能实现
    Android开发中一些常见的问题解决方案
    Android混淆配置文件规范
    android第三方分享之友盟社会化组件
    android一些常用的代码2(收藏)
    svn
    ubuntu 解决中文zip乱码问题
    android优秀Github源码整理
    linux清理内存
    cocos2d-x图层相关 锚点
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6240858.html
Copyright © 2011-2022 走看看