nyoj 765 又见单调递增最长子序列

又见最长单调递增子序列

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述

给一个序列 X(x[1] , x[2] , x[3] ……) ,可以找出他的任意一个单调递增子序列如 x[i1] , x[i2] , x[i3] …… x[in]

它必须满足以下条件。

(1) X[i1] < X[i2] < …… < X[in];

(2) 1<= i1

问题是:

(1)找到最长的单调递增子序列 ,输出长度 len

(2)在每个元素最多只能用一次的情况下,找出长度为len 的单调递增子序列有多少个,输出个数sum。

输入
多组测试数据,不超过100组.
每组输入数据包含两行。
第一行一个数字n,代表序列的长度,第二行包含 n 个数字ai,代表序列中每个元素的值。
n <= 500 , ai <= 10000
输出

每组测试数据输出有两行。第一行输出len,第二行输出sum。



思路 : 将所有在单调递增最长子序列上的点建立边,将长度最长为1的点与源点建边,长度为len 的与汇点建边,中间则将 i,j,建边(dp[i]+1==dp[j]),边的容量为1 ,为保证只用一次,将一个点拆成两个点,容量为1 



#include
using namespace std;
int min ( int x,int y)
{
    return x0)
            {
                level[edge[k].to] = level[top]+1;
                q[rear++] = edge[k].to;
            }
        }

    }
    return false;
}
int dfs(int now,int maxf,int t)
{
    int ret =0,f,k;
    if(now==t)
        return maxf;
    for(int k = head[now]; k!=-1; k = edge[k].next)
    {
        if(level[edge[k].to]==level[now]+1&&edge[k].val>0)
        {
            f = dfs(edge[k].to,min(maxf -ret,edge[k].val),t);
            edge[k].val-=f;
            edge[k^1].val+=f;
            ret+=f;
            if(ret==maxf)
                return ret ;

        }
    }
    if(ret==0)
        level[now] = 0;
    return ret;
}
int dinic(int s,int t)
{
    int ans = 0;
    while(bfs(s,t))
        ans+=dfs(s,inf,t);
    return ans;
}
int  main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(dp,0,sizeof(dp));
        e = 0;
        for(int i = 1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        int len = 1;
        for(int i = 1; i<=n; i++)
        {
            dp[i] = 1;
            for(int j= i-1; j>=1; j--)
            {
                if(a[i]>a[j]&&dp[i]=1; j--)
            {
                if(a[i]>a[j]&&v==dp[j]+1)
                {
                    add_edge(j+n,i,1);
                }
            }
        }
        if(len==1)
        {
            printf("%d\n",len);
            printf("%d\n",n);
            continue;
        }
        int s = 0;
        int t  = 2*n+1;
        for(int i= 1; i<=n; i++)
        {
            if(dp[i]==len)
            {
                add_edge(i+n,t,1);
            }
            if(dp[i]==1)
            {
                add_edge(s,i,1);
            }
            add_edge(i,i+n,1);
        }
        printf("%d\n",len);
        printf("%d\n",dinic(s,t));

    }
    return 0;
}










你可能感兴趣的:(网络流)