hdu 3998 最長上升子序列個數+網絡流 (最多不相交合法路徑數)

Sequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1886    Accepted Submission(s): 687


Problem Description
There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequence of X 
as x[i1], x[i2],...,x[ik], which satisfies follow conditions:
1) x[i1] < x[i2],...,<x[ik];
2) 1<=i1 < i2,...,<ik<=n

As an excellent program designer, you must know how to find the maximum length of the 
increasing sequense, which is defined as s. Now, the next question is how many increasing 
subsequence with s-length can you find out from the sequence X.

For example, in one case, if s = 3, and you can find out 2 such subsequence A and B from X.
1) A = a1, a2, a3. B = b1, b2, b3.
2) Each ai or bj(i,j = 1,2,3) can only be chose once at most.

Now, the question is:
1) Find the maximum length of increasing subsequence of X(i.e. s).
2) Find the number of increasing subsequence with s-length under conditions described (i.e. num).
 

Input
The input file have many cases. Each case will give a integer number n.The next line will 
have n numbers.
 

Output
The output have two line. The first line is s and second line is num.
 

Sample Input
4 3 6 2 5
 

Sample Output
2 2
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  3996 3549 3572 3416 3917 

題目要求找出最長子序列長度,並求出最多有多少個達到最長長度的不相交的子序列。

這題本質上跟hdu 3416問題是一樣,就是找不相交(重疊)的合法路徑最多有多少條。只不過那題的合法路徑是滿足最短路徑(u,v)d[u]+w==d[v],這題的合法路徑則是滿足最長上升(u,v) dp[u]+1==dp[v]。做法是一樣的,先構造出只包含合法路徑的圖,把屬於合法路徑的邊(保證每次跑的流量都是屬於合法路徑)加入到圖中,然後跑一遍最大流算法。

這題爲了處理方便加入0和n+1兩個點,x[0]=-inf,x[n+1]=inf,這樣所有的上升子序列肯定是以0爲起點,以n+1,爲終點。(相當於跟圖加入源點和匯點)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;

const int maxn=1e3+10;
const int maxm=maxn*maxn;
const int inf=0x3f3f3f3f;

struct Edge{
    int v,cap,flow,nxt;
};

int first[maxn],tot;
Edge edge[maxm];
int n,a[maxn];
int dp[maxn];

void addedge(int u, int v, int cap)
{
    edge[tot]=Edge{v,cap,0,first[u]};
    first[u]=tot++;
    edge[tot]=Edge{u,0,0,first[v]};
    first[v]=tot++;
}

void init()
{
    tot=0;
    memset(first, -1, sizeof(first));

    for(int i=1; i<=n; i++){
        scanf("%d", a+i);
    }

    memset(dp, 0, sizeof(dp));
    a[0]=-inf,a[n+1]=inf;
    dp[0]=1;
    for(int i=1; i<=n+1; i++){
        for(int j=0; j<i; j++)
        if(a[j]<a[i]){
            dp[i]=max(dp[i],dp[j]+1);
        }
    }

    for(int i=0; i<=n; i++){
        for(int j=i+1; j<=n+1; j++){
            if(a[i]<a[j] && dp[i]+1==dp[j])
                addedge(i, j, 1);
        }
    }
}

int cur[maxn],dep[maxn],gap[maxn],pre[maxn];

int sap(int st, int ed, int N)
{
    memset(dep,0,sizeof(dep));
    memset(gap,0,sizeof(gap));
    memcpy(cur, first, sizeof(first));
    gap[0]=N;
    int u=st, ans=0;
    pre[u]=-1;
    while(dep[st]<N){
        if(u==ed){
            int mini=inf;
            for(int i=pre[u]; i!=-1; i=pre[edge[i^1].v])
                mini=min(mini,edge[i].cap-edge[i].flow);
            for(int i=pre[u]; i!=-1; i=pre[edge[i^1].v]){
                edge[i].flow+=mini;
                edge[i^1].flow-=mini;
            }
            ans+=mini;
            u=st;
            continue;
        }

        bool flag=false;
        for(int i=cur[u]; i!=-1; i=edge[i].nxt){
            int v=edge[i].v;
            if(edge[i].cap-edge[i].flow>0 && dep[v]+1==dep[u]){
                pre[v]=cur[u]=i;
                u=v;
                flag=true;
                break;
            }
        }

        if(flag) continue;

        int mini=N;
        for(int i=first[u]; i!=-1; i=edge[i].nxt){
            int v=edge[i].v;
            if(edge[i].cap-edge[i].flow>0 && dep[v]<mini){
                cur[u]=i;
                mini=dep[v];
            }
        }
        gap[dep[u]]--;
        if(!gap[dep[u]]) return ans;
        dep[u]=mini+1;
        gap[dep[u]]++;
        if(u!=st)
            u=edge[pre[u]^1].v;
    }
    return ans;
}



int main()
{
    while(cin>>n){
        init();
        int ans=sap(0, n+1, n+2);
        cout<<dp[n+1]-2<<endl<<ans<<endl;
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章