hdu 3998 Sequence(DP+最大流,求最多的不相交路径)

来源:互联网 发布:python java 编辑:程序博客网 时间:2024/06/05 21:50

Sequence

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


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
43 6 2 5
 

Sample Output
22
题意:给出一串序列,求最长上升子序列和最长上升子序列的个数,要求每个数只出现一次。
思路:n^2dp求出第一个解,这时就标记了以每一个数为最后一个数的上升子序列的最大长度。因为要求每个数都只出现一次,所以相当于求最多的不相交路线,可用最大流解出。将每个点拆为i和i+1,连i到i+1的边,容量为1,然后源点到每个标记长度为1的边连一条边,容量为1,标记长度为最大长度的点到汇点连一条边,长度也为1。最后对于每个点,排在它后面的且标记长度比它大1的点之间连容量为1的边。
AC代码:
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <stack>#include <vector>#include <map>#include <cmath>#include <cstdlib>#define L(rt) (rt<<1)#define R(rt) (rt<<1|1)#define ll __int64#define eps 1e-6using namespace std;const int INF = 1000000000;const int maxn = 1005;struct Edge{    int u, v, cap, flow, next;} et[maxn*maxn];int pre[maxn], cur[maxn], dis[maxn],cnt[maxn], low[maxn],  eh[maxn];int a[maxn], dp[maxn];int n, s, t, num;void init(){    memset(eh, -1, sizeof(eh));    num = 0;}void add(int u, int v, int cap, int flow){    Edge e = {u, v, cap, flow, eh[u]};    et[num] = e;    eh[u] = num++;}void addedge(int u, int v, int cap){    add(u, v, cap, 0);    add(v, u, 0, 0);}int isap(int s, int t, int nv){    int u, v, now, flow = 0;    memset(cnt, 0, sizeof(cnt));    memset(low, 0, sizeof(low));    memset(dis, 0, sizeof(dis));    for(u = 0; u <= nv; u++) cur[u] = eh[u];    low[s] =INF, cnt[0] = nv, u = s;    while(dis[s] < nv)    {        for(now = cur[u]; now != -1; now = et[now].next)            if(et[now].cap - et[now].flow && dis[u] == dis[v = et[now].v] + 1) break;        if(now != -1)        {            cur[u] = pre[v] = now;            low[v] = min(et[now].cap - et[now].flow, low[u]);            u = v;            if(u == t)            {                for(; u != s; u = et[pre[u]].u)                {                    et[pre[u]].flow += low[t];                    et[pre[u]^1].flow -= low[t];                }                flow += low[t];                low[s] = INF;            }        }        else        {            if(--cnt[dis[u]] == 0) break;            dis[u] = nv, cur[u] = eh[u];            for(now = eh[u]; now != -1; now = et[now].next)                if(et[now].cap - et[now].flow && dis[u] > dis[et[now].v] + 1)                    dis[u] = dis[et[now].v] + 1;            cnt[dis[u]]++;            if(u != s) u = et[pre[u]].u;        }    }    return flow;}int main(){    while(~scanf("%d", &n))    {        init();        s = 0;        t = 2 * n + 1;        for(int i = 1; i <= n; i++)        scanf("%d", &a[i]);        for(int i = 1; i <= n; i++) dp[i] = 1;        for(int i = 2; i <= n; i++)        for(int j = 1; j < i; j++)            if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);        //for(int i = 1; i <= n; i++) cout<<dp[i]<<endl;        int ans = 0;        for(int i = 1; i <= n; i++)        if(dp[i] > ans) ans = dp[i];        for(int i = 1; i <=n; i++)        {            addedge(i, i + n, 1);            if(dp[i] == 1) addedge(s, i, 1);            if(dp[i] == ans) addedge(i, t, 1);            for(int j = i + 1; j <=n; j++)            if(dp[j] == dp[i] + 1) addedge(i + n, j, 1);        }        printf("%d\n%d\n", ans, isap(s, t, t+1));    }    return 0;}


原创粉丝点击