[HDOJ3998] Sequence(DP,最大流)

题目链接: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 }
时间: 2024-10-10 02:34:46

[HDOJ3998] Sequence(DP,最大流)的相关文章

poj 2081 Recaman&#39;s Sequence (dp)

Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 22566   Accepted: 9697 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already in the sequence,

Codeforces 13C Sequence --DP+离散化

题意:给出一个 n (1 <= n <= 5000)个数的序列 .每个操作可以把 n 个数中的某一个加1 或 减 1.问使这个序列变成非递减的操作数最少是多少 解法:定义dp[i][j]为将前i个数变为以j为结尾的非递减序列的最少操作次数. 则有: dp[i][j] = min(dp[i][j], min(dp[i][k]) + Cost(原来第i个位置上的数转换到j))  (1 <= k <= j) 即前i个数以j结尾的状态可以由前i-1个数以小于等于j的k结尾的状态转移过来,取

hdu6078 Wavel Sequence dp+二维树状数组

//#pragma comment(linker, "/STACK:102400000,102400000") /** 题目:hdu6078 Wavel Sequence 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6078 题意:给定a序列和b序列.从a中取一个子序列x(数的位置顺序保持不变),子序列每个数满足a1<a2>a3<a4>a5<a6... 波浪形 从b中取相同长度的子序列y,也满足波浪形. 如果x

POJ1699:Best Sequence(DP)

Description The twenty-first century is a biology-technology developing century. One of the most attractive and challenging tasks is on the gene project, especially on gene sorting program. Recently we know that a gene is made of DNA. The nucleotide

poj-2478 Farey Sequence(dp,欧拉函数)

题目链接: Farey Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14230   Accepted: 5624 Description The Farey Sequence Fn for any integer n with n >= 2 is the set of irreducible rational numbers a/b with 0 < a < b <= n and gcd

poj 1141 Brackets Sequence dp

 Description Let us define a regular brackets sequence in the following way: 1. Empty sequence is a regular sequence. 2. If S is a regular sequence, then (S) and [S] are both regular sequences. 3. If A and B are regular sequences, then AB is a regu

UVa 10534 Wavio Sequence ( DP 二分 最长递增子序列 )

题意  求一个序列a某一位的最长递增序列(lis)和最长递减序列(lds)中最小值的最大值 开始直接用DP写了   然后就超时了  后来看到别人说要用二分把时间复杂度优化到O(n*logn)   果然如此   用一个栈s保存长度为i的LIS的最小尾部s[i]  top为栈顶即当前LIS的长度  初始s[1]=a[1]  top=1 遍历整个序列  当a[i]>s[top]时  a[i]入栈 in[i]=top   否则 在栈中查找(二分)第一个大于等于a[i]的下标pos  并替换  这样就增加

UVA 348 &amp; ZOJ 1276 Optimal Array Multiplication Sequence(dp , 矩阵链相乘问题)

Optimal Array Multiplication Sequence Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Given two arrays A and B, we can determine the array C = AB using the standard definition of matrix multiplication: The number of

hdu 3998 Sequence LIS+最大流

题意:给定一个序列,求最长上升子序长度以及有多少组,每个元素只能用一次. 思路:先求LIS,记为num,求出以每个点为末尾的最长子序列长度.窝们将每个点点拆成i和i',i --> i' 容量为1,源点连接d[ i ]=1的点,容 量为1,汇点连接d[ i ]=num的点,容量为1.对于j<i, a[ j ] < a[ i ],d[ i ] = d[ j ] + 1的情况,j' --> i 连一条容量为1的边,跑最大流即可.详见代码: /***********************