• 【[网络流二十四题]最长不下降子序列问题】


    题目

    啥都不会只能来写写题解了

    第一问先搞一个(dp)吧,小学生水平的(dp)

    第二问要求每一个点只能使用一次,显然要先拆点,把(i)拆成(i)(i'),之后(i)(i')连容量为(1)的边

    之后能产生长度为(ans)的LIS需要满足什么条件呢,显然得从一个(dp[i]=1)的点开始,从一个(dp[i]=ans)的点结束,否则就不可能产生长度为(ans)的LIS了

    同时我们还得考虑到我们这是一个(dp),所以只能是让(i)的所有转移点向(i)连边

    第三问取消(1)(n)的限制就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define maxn 1105
    #define re register 
    #define LL long long
    #define inf 99999999
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
        char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
        return x;
    }
    struct E{int v,nxt,w,f;}e[2000005];
    int dp[maxn],a[maxn],ans,n,num=1,S,T,tot,cnt;
    int d[maxn],head[maxn],cur[maxn];
    inline void add(int x,int y,int z) {e[++num].v=y;e[num].w=z;e[num].nxt=head[x];head[x]=num;}
    inline void C(int x,int y,int z) {add(x,y,z),add(y,x,0);}
    inline int BFS()
    {
        std::queue<int> q;
        for(re int i=S;i<=T;i++) d[i]=0,cur[i]=head[i];
        d[S]=1,q.push(S);
        while(!q.empty())
        {
            int k=q.front();q.pop();
            for(re int i=head[k];i;i=e[i].nxt)
            if(!d[e[i].v]&&e[i].w>e[i].f) d[e[i].v]=d[k]+1,q.push(e[i].v);
        }
        return d[T];
    }
    int dfs(int x,int now)
    {
        if(x==T||!now) return now;
        int flow=0,ff;
        for(re int& i=cur[x];i;i=e[i].nxt)
        if(d[x]+1==d[e[i].v])
        {
            ff=dfs(e[i].v,min(e[i].w-e[i].f,now));
            if(ff<=0) continue;
            now-=ff,flow+=ff;
            e[i].f+=ff,e[i^1].f-=ff;
            if(!now) break;
        }
        return flow;
    }
    int main()
    {
        n=read();
        if(n==1) {puts("1");puts("1"),puts("1");return 0;}
        for(re int i=1;i<=n;i++) a[i]=read(),dp[i]=1;
        for(re int i=1;i<=n;i++)
            for(re int j=1;j<i;j++)
                if(a[j]<=a[i]) dp[i]=max(dp[i],dp[j]+1);
        for(re int i=1;i<=n;i++) ans=max(ans,dp[i]);
        S=0,T=n+n+1;	
        for(re int i=1;i<=n;i++) C(i,i+n,1);
        for(re int i=1;i<=n;i++)
            if(dp[i]==1) C(S,i,1);
        for(re int i=1;i<=n;i++)
            if(dp[i]==ans) C(i+n,T,1);
        for(re int i=1;i<=n;i++)
            for(re int j=1;j<i;j++)
                if(a[j]<=a[i]&&dp[i]==dp[j]+1) C(j+n,i,1);
        while(BFS()) tot+=dfs(S,inf);
        num=1;memset(e,0,sizeof(e)),memset(head,0,sizeof(head));
        for(re int i=2;i<n;i++) C(i,i+n,1);
        for(re int i=2;i<n;i++)
            if(dp[i]==1) C(S,i,1);
        for(re int i=2;i<n;i++)
            if(dp[i]==ans) C(i+n,T,1);
        C(1,1+n,inf),C(n,n+n,inf);
        if(dp[1]==1) C(S,1,inf);
        if(dp[1]==ans) C(1+n,T,1);
        if(dp[n]==1) C(S,n,1);
        if(dp[n]==ans) C(n+n,T,inf);
        for(re int i=1;i<=n;i++)
            for(re int j=1;j<i;j++)
                if(a[j]<=a[i]&&dp[i]==dp[j]+1) C(j+n,i,1);
        while(BFS()) cnt+=dfs(S,inf);
        printf("%d
    %d
    %d
    ",ans,tot,cnt);
        return 0;
    }
    
  • 相关阅读:
    Medium | LeetCode 148. 排序链表 | 归并排序(递归)
    Hard | LeetCode 4. 寻找两个正序数组的中位数 | 二分法
    Medium | LeetCode 341. 扁平化嵌套列表迭代器 | 递归 | 栈
    Hard | LeetCode 312. 戳气球 | 递归+记忆化数组 | 动态规划
    如何删除万能输入法
    javaweb 怎么获取路径
    Controller 返回 json那些小事
    螺旋矩阵
    javaweb怎么使用html
    tomcat中文乱码
  • 原文地址:https://www.cnblogs.com/asuldb/p/10293207.html
Copyright © 2020-2023  润新知