• 网络流24题 最长递增子序列问题


    题目描述

    «问题描述:

    给定正整数序列x1,...,xn 。

    (1)计算其最长递增子序列的长度s。

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

    (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。

    «编程任务:

    设计有效算法完成(1)(2)(3)提出的计算任务。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    4
    3 6 2 5
    输出样例#1:
    2
    2
    3

    byvoid:

    【问题分析】

    第一问是LIS,动态规划求解,第二问和第三问用网络最大流解决。

    【建模方法】

    首先动态规划求出F[i],表示以第i位为开头的最长上升序列的长度,求出最长上升序列长度K。

    1、把序列每位i拆成两个点<i.a>和<i.b>,从<i.a>到<i.b>连接一条容量为1的有向边。
    2、建立附加源S和汇T,如果序列第i位有F[i]=K,从S到<i.a>连接一条容量为1的有向边。
    3、如果F[i]=1,从<i.b>到T连接一条容量为1的有向边。
    4、如果j>i且A[i] < A[j]且F[j]+1=F[i],从<i.b>到<j.a>连接一条容量为1的有向边。

    求网络最大流,就是第二问的结果。把边(<1.a>,<1.b>)(<N.a>,<N.b>)(S,<1.a>)(<N.b>,T)这四条边的容量修改为无穷大,再求一次网络最大流,就是第三问结果。

    【建模分析】

    上述建模方法是应用了一种分层图的思想,把图每个顶点i按照F[i]的不同分为了若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长上升子序列。由于序列中每个点要不可重复地取出,需要把每个点拆分成两个点。单位网络的最大流就是增广路的条数,所以最大流量就是第二问结果。第三问特殊地要求x1和xn可以重复使用,只需取消这两个点相关边的流量限制,求网络最大流即可。


    其实比较好想的,能转移就连一条容量为1的边,选择次数不限制就INF
    注意:
    全部递减特判
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=1005,M=1e6,INF=1e9;
    int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n,a[N],f[N],g[N],s,t,l;
    void dp(){
        for(int i=1;i<=n;i++) g[i]=INF;
        for(int i=1;i<=n;i++){
            int k=upper_bound(g+1,g+1+n,a[i])-g;
            f[i]=k;
            g[k]=a[i];
            l=max(l,f[i]);
        }
    }
    struct edge{
        int v,ne,c,f;
    }e[M<<1];
    int cnt,h[N];
    inline void ins(int u,int v,int c){
        cnt++;
        e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt;
    }
    void build(){
        cnt=0;
        memset(h,0,sizeof(h));
        for(int i=1;i<=n;i++){
            if(f[i]==1) ins(s,i,1);
            ins(i,i+n,1);
            if(f[i]==l) ins(i+n,t,1);
            for(int j=1;j<i;j++) if(a[j]<=a[i]&&f[j]+1==f[i]) ins(j+n,i,1);
        }
    }
    void build2(){
        cnt=0;
        memset(h,0,sizeof(h));
        for(int i=1;i<=n;i++){
            if(i==1||i==n){
                if(f[i]==1) ins(s,i,INF);
                ins(i,i+n,INF);
                if(f[i]==l) ins(i+n,t,INF);
            }else{
                if(f[i]==1) ins(s,i,1);
                ins(i,i+n,1);
                if(f[i]==l) ins(i+n,t,1);
            }
            for(int j=1;j<i;j++) if(a[j]<=a[i]&&f[j]+1==f[i]) ins(j+n,i,1);
        }
    }
    int vis[N],d[N],q[N],head=1,tail=1;
    bool bfs(){
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        head=tail=1;
        q[tail++]=s;d[s]=0;vis[s]=1;
        while(head!=tail){
            int u=q[head++];
            for(int i=h[u];i;i=e[i].ne){
                int v=e[i].v;
                if(!vis[v]&&e[i].c>e[i].f){
                    vis[v]=1;d[v]=d[u]+1;
                    q[tail++]=v;
                    if(v==t) return 1;
                }
            }
        }
        return 0;
    }
    int cur[N];
    int dfs(int u,int a){
        if(u==t||a==0) return a;
        int flow=0,f;
        for(int &i=cur[u];i;i=e[i].ne){
            int v=e[i].v;
            if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){
                flow+=f;
                e[i].f+=f;
                e[((i-1)^1)+1].f-=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int dinic(){
        int flow=0;
        while(bfs()){//cout<<"p";
            for(int i=s;i<=t;i++) cur[i]=h[i];
            flow+=dfs(s,INF);
        }
        return flow;
    }
    int main(){
        n=read();s=1;t=n+n+1;
        for(int i=1;i<=n;i++) a[i]=read();
        dp();printf("%d
    ",l);
        if(l==1) {printf("%d
    %d",n,n);return 0;}
        build();
        printf("%d
    ",dinic());
        build2();
        printf("%d",dinic());
    }



  • 相关阅读:
    html基础起航
    必杀技———SQL基础整理系列(一)
    JavaScript代码段整理笔记系列(一)
    与JSP的初次邂逅……
    产品第二篇
    产品第一篇
    进程在后台可靠运行的几种方法
    Vue.js模板语法
    更靠谱的横竖屏检测方法
    浮动【电梯】或【回到顶部】小插件:iElevator.js
  • 原文地址:https://www.cnblogs.com/candy99/p/6124094.html
Copyright © 2020-2023  润新知