HDU 3998 Sequence

题意:给出一个n个数字的序列,求最长上升子序列长度,并求出最多可以找出多少个最长上升子序列(每个位置上的数字只能在找出的序列中出现一次)

只能出现一次,还是可以联想到最大流的。而对于一个已经给定了的长度,貌似想控制在网络中的路径长度不太可能。假定每个位置上的当前最长上升子序列的标记为dp(i)。每个流会对应一种物理方案,那么必须是dp(j)=dp(i)+1,(j>i),所以,对于所有的符合条件的i,j,有边(i',j,1)。另外由于是每个数字只可以使用一次,所以肯定对应一条边(i,i',1),对于所有dp(i)=1的点,对应边(S,i,1),对于所有dp(i)=ans的点,对应边(i',T,1),这样一来,跑S->T的最大流就可以得出答案。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define INF 0x7fffffff
 6 #define maxn 1<<13
 7 #define maxm 1<<17
 8 using namespace std;
 9 int v[maxm],next[maxm],w[maxm];
10 int first[maxn],d[maxn],work[maxn],q[maxn];
11 int e,S,T;
12 int dp[maxn],s[maxn];
13 void init(){
14     e = 0;
15     memset(first,-1,sizeof(first));
16 }
17 
18 void add_edge(int a,int b,int c){
19     //printf("add:%d to %d,cap = %d
",a,b,c);
20     v[e] = b;w[e] = c;next[e] = first[a];first[a] = e++;
21     v[e] = a;w[e] = 0;next[e] = first[b];first[b] = e++;
22 }
23 
24 int bfs(){
25     int rear = 0;
26     memset(d,-1,sizeof(d));
27     d[S] = 0;q[rear++] = S;
28     for(int i = 0;i < rear;i++){
29         for(int j = first[q[i]];j != -1;j = next[j])
30             if(w[j] && d[v[j]] == -1){
31                 d[v[j]] = d[q[i]] + 1;
32                 q[rear++] = v[j];
33                 if(v[j] == T)   return 1;
34             }
35     }
36     return 0;
37 }
38 
39 int dfs(int cur,int a){
40     if(cur == T)    return a;
41     for(int &i = work[cur];i != -1;i = next[i]){
42         if(w[i] && d[v[i]] == d[cur] + 1)
43             if(int t = dfs(v[i],min(a,w[i]))){
44                 w[i] -= t;w[i^1] += t;
45                 return t;
46             }
47     }
48     return 0;
49 }
50 
51 int dinic(){
52     int ans = 0;
53     while(bfs()){
54         memcpy(work,first,sizeof(first));
55         while(int t = dfs(S,INF))   ans += t;
56     }
57     return ans;
58 }
59 
60 int main()
61 {
62     int n;
63     while(scanf("%d",&n) == 1){
64         for(int i = 1;i <= n;i++){
65             scanf("%d",&s[i]);
66             dp[i] = 1;
67         }
68         int ans = 1;
69         for(int i = 2;i <= n;i++)
70             for(int j = 1;j < i;j++)
71                 if(s[i] > s[j] && dp[j] >= dp[i]){
72                     dp[i] = dp[j] + 1;
73                     ans = max(ans,dp[i]);
74                 }
75         init();
76         S = 0,T = n*2+1;
77         for(int i = 1;i <= n;i++){
78             add_edge(i,i+n,1);
79             if(dp[i] == 1)      add_edge(S,i,1);
80             if(dp[i] == ans)    add_edge(i+n,T,1);
81             for(int j = i+1;j <= n;j++){
82                 if(dp[j] == dp[i] + 1)  add_edge(i+n,j,1);
83             }
84         }
85         printf("%d
%d
",ans,dinic());
86     }
87     return 0;
88 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3385498.html