zoukankan      html  css  js  c++  java
  • 网络流24题 P2766 最长不下降子序列问题

    题目描述

    «问题描述:

    给定正整数序列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

    解析

    (1) n^2的dp  求出S
    
    (2)从源点向dp[i]=1的点连一条容量为1的边,dp[i]=S的点向汇点连一条容量为1的边。
    
        因为每个点只能用一次,所以我们还要把一个点拆成两个i 和 i+n,在它们之间连一条容量为1的边。
    
        之后n^2枚举每两个点,若两个点i,j满足a[j]<=a[i]且dp[i]=dp[j]+1,则在i+n,j之间连一条容量为1的边。
    
        建好图后跑一边最大流,就是第二问的答案。
    
    (3)将源点向dp[i]=1的点连的边的容量改为inf,dp[i]=1的点与拆出来的点边权也要设为inf。同理汇点也一样。 

    代码

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e3+20,mod=1e9+7,inf=0x3f3f3f3f;
    typedef long long ll;
    struct edge
    {
        int from,to,c,f;
        edge(int u,int v,int c,int f):from(u),to(v),c(c),f(f) {}
    };
    int n,m;
    vector<edge> edges;
    vector<int> g[maxn];
    int d[maxn];//从起点到i的距离
    int cur[maxn];//当前弧下标
    void init(int N)
    {
        for(int i=0; i<=N; i++) g[i].clear();
        edges.clear();
    }
    void addedge(int from,int to,int c) //加边 支持重边
    {
        edges.push_back(edge(from,to,c,0));
        edges.push_back(edge(to,from,0,0));
        int siz=edges.size();
        g[from].push_back(siz-2);
        g[to].push_back(siz-1);
    }
    int bfs(int s,int t) //构造一次层次图
    {
        memset(d,-1,sizeof(d));
        queue<int> q;
        q.push(s);
        d[s]=0;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=0;i<g[x].size();i++)
            {
                edge &e=edges[g[x][i]];
                if(d[e.to]<0&&e.f<e.c) //d[e.to]=-1表示没访问过
                {
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return d[t];
    }
    int dfs(int x,int a,int t) // a表示x点能接收的量
    {
        if(x==t||a==0)return a;
        int flow=0,f;//flow总的增量 f一条增广路的增量
        for(int &i=cur[x];i<g[x].size();i++)//cur[i] &引用修改其值 从上次考虑的弧
        {
            edge &e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.c-e.f),t))>0)    //按照层次图增广 满足容量限制
            {
                e.f+=f;
                edges[g[x][i]^1].f-=f;  //修改流量
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int maxflow(int s,int t)
    {
        int flow=0;
        while(bfs(s,t)!=-1) //等于-1代表构造层次图失败 结束
        {
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,inf,t);
        }
        return flow;
    }
    int a[1005],dp[1005];
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            int maxdp=0;
            for(int i=1;i<=n;i++){
                dp[i]=1;
                for(int j=1;j<i;j++){
                    if(a[j]<=a[i])
                        dp[i]=max(dp[i],dp[j]+1);
                }
                maxdp=max(maxdp,dp[i]);
            }
            printf("%d
    ",maxdp);
            if(maxdp==1){
                printf("%d
    %d
    ",n,n);
                continue;
            }
            init(2*n+1);
            for(int i=1;i<=n;i++){
                if(dp[i]==1) addedge(0,i,1);
                if(dp[i]==maxdp) addedge(i+n,2*n+1,1);
                addedge(i,i+n,1);
                for(int j=1;j<i;j++){
                    if(a[j]<=a[i]&&dp[i]==dp[j]+1)
                        addedge(j+n,i,1);
                }
            }
            printf("%d
    ",maxflow(0,2*n+1));
            init(2*n+1);
            for(int i=1;i<=n;i++){
                if(dp[i]==1)addedge(0,i,inf);
                if(dp[i]==maxdp) addedge(i+n,2*n+1,inf);
                if(dp[i]==1||dp[i]==maxdp)addedge(i,i+n,inf);
                else addedge(i,i+n,1);
                for(int j=1;j<i;j++){
                    if(a[j]<=a[i]&&dp[i]==dp[j]+1)
                        addedge(j+n,i,1);
                }
            }
            printf("%d
    ",maxflow(0,2*n+1));
        }
    }
  • 相关阅读:
    怎样在UIViewController的生命周期函数中判断是push或者是pop触发的生命周期函数
    配环境
    assert 断言
    mysql:创建新库,新表,查看character
    Python中的[...]是什么?
    同时安装了python3.4和python3.5,如何使用pip?
    亲测可用的优雅的在已经安装了python的Ubuntu上安装python3.5
    如何截网页长图?
    安装tensorflow
    unable to lock the administration directory (/var/lib/dpkg/) is another process using it
  • 原文地址:https://www.cnblogs.com/stranger-/p/11271481.html
Copyright © 2011-2022 走看看