1. 程式人生 > >[HDOJ3998] Sequence(DP,最大流)

[HDOJ3998] Sequence(DP,最大流)

好的 hdoj 一個點 include type div c++ cnblogs span

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=3998

給數字,問LIS以及每一個數字只取一次,最多能取多少個LIS。

LIS直接O(n^2) dp即可。

關鍵是怎麽在統計最多能取多少個不相交的LIS:

每個數作為一個點,假如dp(i)=1,則說明這個點作為起點是不虧的,假如dp(i)=LIS,那麽這個點肯定有機會是最後一個點。這樣源點和匯點的邊就建好:

源點 到 dp(i)=1 容量為1

dp(i)=LIS 到 匯點 容量為1

還要描述點與點之間的關系,所以不要忘記拆點。左半部分記為A集合,右半部分記為B集合。

A到B同位置的點要連一條邊,容量為1。保證可以從A側到B側。

接下來可以枚舉任意兩個點i j,滿足恰好的遞推關系就行:i > j && x(i)>x(j) && dp(i)=dp(j)+1,則j到i連一條邊,容量為1(註意是從B集合到A集合哦,不然的話只有A到B是不能滿足匹配的)。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 typedef struct Edge {
  5     int u, v, w, next;
  6 }Edge;
  7 
  8 const int inf = 0x7f7f7f7f;
9 const int maxn = 6660; 10 11 int cnt, dhead[maxn]; 12 int cur[maxn], dd[maxn]; 13 Edge dedge[maxn<<8]; 14 int S, T, N; 15 16 void init() { 17 memset(dhead, -1, sizeof(dhead)); 18 for(int i = 0; i < maxn; i++) dedge[i].next = -1; 19 S = 0; cnt = 0; 20 } 21 22 void adde(int
u, int v, int w, int c1=0) { 23 dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w; 24 dedge[cnt].next = dhead[u]; dhead[u] = cnt++; 25 dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1; 26 dedge[cnt].next = dhead[v]; dhead[v] = cnt++; 27 } 28 29 bool bfs(int s, int t, int n) { 30 queue<int> q; 31 for(int i = 0; i < n; i++) dd[i] = inf; 32 dd[s] = 0; 33 q.push(s); 34 while(!q.empty()) { 35 int u = q.front(); q.pop(); 36 for(int i = dhead[u]; ~i; i = dedge[i].next) { 37 if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) { 38 dd[dedge[i].v] = dd[u] + 1; 39 if(dedge[i].v == t) return 1; 40 q.push(dedge[i].v); 41 } 42 } 43 } 44 return 0; 45 } 46 47 int dinic(int s, int t, int n) { 48 int st[maxn], top; 49 int u; 50 int flow = 0; 51 while(bfs(s, t, n)) { 52 for(int i = 0; i < n; i++) cur[i] = dhead[i]; 53 u = s; top = 0; 54 while(cur[s] != -1) { 55 if(u == t) { 56 int tp = inf; 57 for(int i = top - 1; i >= 0; i--) { 58 tp = min(tp, dedge[st[i]].w); 59 } 60 flow += tp; 61 for(int i = top - 1; i >= 0; i--) { 62 dedge[st[i]].w -= tp; 63 dedge[st[i] ^ 1].w += tp; 64 if(dedge[st[i]].w == 0) top = i; 65 } 66 u = dedge[st[top]].u; 67 } 68 else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) { 69 st[top++] = cur[u]; 70 u = dedge[cur[u]].v; 71 } 72 else { 73 while(u != s && cur[u] == -1) { 74 u = dedge[st[--top]].u; 75 } 76 cur[u] = dedge[cur[u]].next; 77 } 78 } 79 } 80 return flow; 81 } 82 83 int n; 84 int x[maxn]; 85 int dp[maxn]; 86 int ret; 87 88 void work1() { 89 ret = 0; 90 memset(dp, 0, sizeof(dp)); 91 for(int i = 1; i <= n; i++) { 92 dp[i] = 1; 93 for(int j = 1; j <= i; j++) { 94 if(x[i] > x[j]) dp[i] = max(dp[i], dp[j]+1); 95 } 96 ret = max(ret, dp[i]); 97 } 98 printf("%d\n", ret); 99 } 100 101 void work2() { 102 if(ret == 1) { 103 printf("%d\n", n); 104 return; 105 } 106 init(); 107 S = 0, T = 2 * n + 1, N = T + 1; 108 for(int i = 1; i <= n; i++) { 109 adde(i, i+n, 1); 110 if(dp[i] == 1) adde(S, i, 1); 111 if(dp[i] == ret) adde(i+n, T, 1); 112 } 113 for(int i = 2; i <= n; i++) { 114 for(int j = 1; j < i; j++) { 115 if(x[i] > x[j] && dp[i] == dp[j] + 1) { 116 adde(j+n, i, 1); 117 } 118 } 119 } 120 cout << dinic(S, T, N) << endl; 121 } 122 123 int main() { 124 // freopen("in", "r", stdin); 125 while(~scanf("%d",&n)) { 126 init(); 127 for(int i = 1; i <= n; i++) scanf("%d", &x[i]); 128 work1(); work2(); 129 } 130 return 0; 131 }

[HDOJ3998] Sequence(DP,最大流)