网络流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
 
原文地址:https://www.cnblogs.com/tian-luo/p/9714837.html