zoukankan      html  css  js  c++  java
  • 网络流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());
    }



  • 相关阅读:
    HDU 1800 Flying to the Mars 字典树,STL中的map ,哈希树
    字典树 HDU 1075 What Are You Talking About
    字典树 HDU 1251 统计难题
    最小生成树prim算法 POJ2031
    POJ 1287 Networking 最小生成树
    次小生成树 POJ 2728
    最短路N题Tram SPFA
    poj2236 并查集
    POJ 1611并查集
    Number Sequence
  • 原文地址:https://www.cnblogs.com/candy99/p/6124094.html
Copyright © 2011-2022 走看看