最长不下降子序列问题

问题描述

给定正整数序列x1,...,xn 。

(1)计算其最长不下降子序列的长度s。

(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。

(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。

输入格式

第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。

输出格式

第1 行是最长不下降子序列的长度s。第2行是可取出的长度为s 的不下降子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的不下降子序列个数。

 


首先用n^2算出f[i],开头为i的最长不下降子序列

 

通过放f[i]分层建图:

1、把数列每位i拆成两个点,连接一条容量为1的有向边。

2、建立源点s和汇点t,如果数列第i位有f[i]=ans,从s到<i.a>连接一条容量为1的有向边。如果f[i]=1,从<i.b>到T连接一条容量为1的有向边。

3、如果i<j且a[i] < =a[j]且f[j]+1=f[i],从<i.b>到<j.a>连接一条容量为1的有向边。

保证每一条从s到t的路径都是满足长度为ans的序列

第二问:序列最多能得到不重复下标的序列数

第三问:序列最多能得到(除了1,n)不重复下标的序列数;

#include<bits/stdc++.h>
#define re return
#define dec(i,l,r) for(int i=l;i>=r;--i)
#define inc(i,l,r) for(int i=l;i<=r;++i)

using namespace std;

template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
} 

const int maxn=2000,inf=2147483647;
int n,m,k=1,s,t,hd[maxn],cur[maxn],a[505],f[505];
int deep[maxn];

struct node{
    int to,nt,flow;
}e[100005];

inline void add(int x,int y,int flow)
{
    e[++k].to=y;e[k].nt=hd[x];hd[x]=k;e[k].flow=flow;
    e[++k].to=x;e[k].nt=hd[y];hd[y]=k;e[k].flow=0;
}

inline bool bfs()
{
    inc(i,1,t)deep[i]=0;
    deep[s]=1;
    queue<int>q;
    q.push(s);
    
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to;
            if(deep[v]==0&&e[i].flow)
            {
                deep[v]=deep[x]+1;
                if(v==t)re 1;
                q.push(v);
            }
        }
    }
    re 0;
}


inline int dfs(int x,int flow)
{
    if(x==t)re flow;
    int delta=flow;
    for(int &i=cur[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(deep[v]==deep[x]+1&&e[i].flow)
        {
            int d=dfs(v,min(delta,e[i].flow));
            e[i].flow-=d;
            e[i^1].flow+=d;
            delta-=d;
            if(!delta)re flow; 
            
        }
    }
    re flow-delta;
}

int main()
{
//    freopen("in.txt","r",stdin);
    int ans=0;
    rd(n);
    s=n+n+1;t=s+1;
    inc(i,1,n)rd(a[i]);
    dec(i,n,1)
    {
        f[i]=1;
        inc(j,i+1,n)
        if(a[i]<=a[j])f[i]=max(f[i],f[j]+1);
        ans=max(ans,f[i]);
    }
    
    printf("%d\n",ans);
    inc(i,1,n)
    {
        add(i,i+n,1);
        if(f[i]==ans)
        add(s,i,1);
        if(f[i]==1)
        add(i+n,t,1); 
        
        inc(j,i+1,n)
        if(a[i]<=a[j]&&f[i]==f[j]+1)
        add(i+n,j,1);
    }
    
    int ANS=ans;
    ans=0;
    while(bfs())
    {
        inc(i,1,t)cur[i]=hd[i];
        ans+=dfs(s,inf);
    }
    printf("%d\n",ans);
    

    for(int i=2;i<=k;i+=2)
    {
        e[i].flow+=e[i^1].flow;
        e[i^1].flow=0;
    }
    if(f[1]==ANS)add(s,1,inf);
//保证建图正确,s与f[i]=ans的点连边
    add(1,n+1,inf);
    add(n,n+n,inf);
    add(n+n,t,inf);
    ans=0;
    while(bfs())
    {
        inc(i,1,t)cur[i]=hd[i];
        ans+=dfs(s,inf);
    }
    printf("%d\n",ans);
    re 0;
} 

 

posted @ 2019-08-15 21:53  凉如水  阅读(304)  评论(0编辑  收藏  举报