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


    题目大意:给定长度为n的序列a,求:1.最长递增子序列长度;2.最多选出几个不相交的最长递增子序列;3.最多选出几种在除了第1个和第n个以外的地方不相交的最长递增子序列。(n<=1000)

    思路:先倒着DP,求出f[i]表示以a[i]开头的最长的递增子序列长度,然后建图,若f[i]=最长递增子序列长度则S向i连1,若f[i]=1则i向T连1,若i<j且a[i]<a[j]且f[i]=f[j]+1则i向j连1,为保证每个点只被流一次,拆成入点和出点,流量限制1,跑最大流即可解决第二问,点1和点n的流量限制改为INF则可解决第三问,这样建图边数看上去是O(n^2)的,实际上比这小很多,是可过的,另外边其实是可以优化到O(n)的,由于f[i]相同的点若下标递增则a[i]不升,我们对每个i找到最大的j满足a[i]<a[j]且f[i]=f[j]+1连1,再找到最大的j满足j<i且f[i]=f[j]连INF,容易发现这样建图和原图效果是一样的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 1000
    #define MV 2000
    #define ME 1000000
    #define S MV+1
    #define T MV+2
    #define INF 0x7FFFFFFF
    struct edge{int nx,t,w;}e[ME*2+5];
    int n,h[MV+5],en=1,a[MN+5],f[MN+5],mx,d[MV+5],q[MV+5],qn,c[MV+5];
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    void build(int v)
    {
        for(int i=1;i<=n;++i)
        {
            ins(i,i+n,(i>1&&i<n)||!v?1:INF);
            if(!f[i])ins(i+n,T,i==n&&v?INF:1);
            if(f[i]==mx)ins(S,i,i==1&&v?INF:1);
            for(int j=i;++j<=n;)if(a[i]<=a[j]&&f[i]==f[j]+1)ins(i+n,j,1);
        }
    }
    bool bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
            if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    int dfs(int x,int r)
    {
        if(x==T)return r;
        int k,u=0;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1)
        {
            k=dfs(e[i].t,min(r-u,e[i].w));
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(u==r)return u;
        }
        return d[x]=0,u;
    }
    int main()
    {
        int i,j,ans=0;n=read();
        for(i=1;i<=n;++i)a[i]=read();
        for(i=n;--i;mx=max(mx,f[i]))for(j=n;j>i;--j)
            if(a[i]<=a[j])f[i]=max(f[i],f[j]+1);
        printf("%d
    ",mx+1);
        for(build(0);bfs();)ans+=dfs(S,INF);
        printf("%d
    ",ans);
        memset(h,ans=0,sizeof(h));build(en=1);
        while(bfs())ans+=dfs(S,INF);
        printf("%d",ans);
    }
  • 相关阅读:
    【算法】二分图的判定
    【模板】并查集 两种路径压缩写法(类模板和函数模板)
    【模板】堆的结构
    新疆大学OJ(ACM) 1099: 数列有序!
    新疆大学OJ(ACM) 1047: string 字符串排序
    新疆大学(新大)OJ xju 1010: 四个年级 C++ STL map 将4层循环优化成2层循环可解
    新疆大学(新大)OJ xju 1009: 一带一路 prim求最短路径+O(n)素数筛选
    新疆大学(新大)OJ xju 1006: 比赛排名 第二类斯特林数+阶乘
    【算法】第二类斯特林数Stirling
    【复习资料】编译原理中:短语,直接短语,句柄
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170320P.html
Copyright © 2020-2023  润新知