• 网络流24题- 最长不下降子序列问题


    最长不下降子序列问题

    时空限制1000ms / 128MB

    题目描述

    «问题描述:

    给定正整数序列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 的不下降子序列个数。

    输入输出样例

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

    说明

    n500

    题目链接:https://www.luogu.org/problemnew/show/P2766


    最大流。第一问可用dp解决。对于第二问,设最长不下降子序列的长度为k,问题难在怎么满足从源点到汇点的一条增广路恰好选取k个不下降的数。我们可从第一问的dp数组上做文章,dp[i]代表以第i个数结尾的最长不下降子序列的长度是多少。对每一个数ai,对于它后面的数aj,若ai<=aj且dp[i]+1=dp[j],则从i向j连一条边。最后源点与dp值为1的点连边,汇点与dp值为k的点连边。这样就保证每一条从源点到汇点的可行流,都恰好经过k个不下降的数。还有一点要说明的是,对于每一个点,都要拆点来限制每个点只能被选一次。第三问直接修改第二问中对点的限制就好了。
    #include<bits/stdc++.h>
    #define INF LLONG_MAX/2
    #define N 1005
    using namespace std;
    
    struct ss
    {
        int v,next;
        long long flow;
    };
    int head[N],now_edge=0,S,T;
    ss edg[N*N];
    
    void init()
    {
        now_edge=0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,long long flow)
    {
        edg[now_edge]=(ss){v,head[u],flow};
        head[u]=now_edge++;
        edg[now_edge]=(ss){u,head[v],0};
        head[v]=now_edge++;
    }
    
    int dis[N];
    
    int bfs()
    {
        memset(dis,0,sizeof(dis));
        queue<int>q;
        q.push(S);
        dis[S]=1;
        
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            
            for(int i=head[now];i!=-1;i=edg[i].next)
            {
                ss &e=edg[i];
                if(e.flow>0&&dis[e.v]==0)
                {
                    dis[e.v]=dis[now]+1;
                    q.push(e.v);
                }
            }
        }
        
        if(dis[T]==0)return 0;
        return 1;
    }
    
    int current[N];
    long long dfs(int x,long long maxflow)
    {
        if(x==T)return maxflow;
        for(int i=current[x];i!=-1;i=edg[i].next)
        {
            current[x]=i;
            
            ss &e=edg[i];
            if(e.flow>0&&dis[e.v]==dis[x]+1)
            {
                long long flow=dfs(e.v,min(maxflow,e.flow));
                
                if(flow!=0)
                {
                    e.flow-=flow;
                    edg[i^1].flow+=flow;
                    return flow;
                }
            }
        }
        return 0;
    }
    
    long long dinic()
    {
        long long ans=0,flow;
        
        while(bfs())
        {
            for(int i=0;i<N;i++)current[i]=head[i];
            while(flow=dfs(S,INF))ans+=flow;
        }
        return ans;
    }
    
    int main()
    {
        int n;
        int arr[N];
        int dp[N]={0};
        int ans1=1,ans2=0;
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&arr[i]);
        dp[1]=1;
        
        for(int i=2;i<=n;i++)
        {
            int Max=0;
            for(int j=1;j<i;j++)if(arr[j]<=arr[i])Max=max(Max,dp[j]);
            dp[i]=Max+1;
            ans1=max(ans1,dp[i]);
        }
        printf("%d
    ",ans1);
        
        S=n*2+1;
        T=S+1;
        
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            if(dp[j]==dp[i]+1&&arr[j]>=arr[i])addedge(2*i,2*j-1,1);
            
            addedge(i*2-1,i*2,1);
            if(dp[i]==1)addedge(S,2*i-1,1);
            if(dp[i]==ans1)addedge(2*i,T,1);
        }
        ans2=dinic();
        
        printf("%d
    ",ans2);
        addedge(1,2,INF);
        addedge(2*n-1,2*n,INF);
        addedge(S,1,INF);
        if(dp[n]==ans1)addedge(2*n,T,INF);
        
        ans2+=(int)dinic();
        printf("%d
    ",ans2);
        return 0;
    }
    View Code
     
  • 相关阅读:
    『Linux学习笔记』0. 在Windows中运行Linux内核(Ubuntu)
    『Linux学习笔记』10. 文本编辑器
    『Linux学习笔记』9. 进程
    九种乱码解决办法(非原创)
    Eclipse中10个最有用的快捷键组合
    MVC(Model View Controller)框架
    ognl表达式
    统计一段文字中数组、中文、英文字母、空格以及其他特殊字符出现的次数
    java基础知识4
    java基础知识3
  • 原文地址:https://www.cnblogs.com/tian-luo/p/9714837.html
Copyright © 2020-2023  润新知