[题解] PowerOJ 1741 最长递增子序列问题 (最大流)

- 传送门 -

 https://www.oj.swust.edu.cn/problem/show/1741

#  1741: 最长递增子序列问题

Time Limit: 1000 MS Memory Limit: 65536 KB
Total Submit: 379 Accepted: 67 Page View: 1046

Description

给定正整数序列x1 ,... , xn 。 (1)计算其最长递增子序列的长度s。(严格递增) (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。 (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长 度为s的递增子序列。 编程任务: 设计有效算法完成(1)(2)(3)提出的计算任务。

Input

由文件input.txt提供输入数据。文件第1 行有1个正整数n(n<400),表示给定序列的长度。接 下来的1 行有n个正整数 x1 , ... , xn。

Output

程序运行结束时,将任务(1)(2)(3)的解答输出到文件output.txt中。第1 行是最长 递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出 的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。

Source

线性规划与网络流24题

 

- 思路 -

 第一问dp.
 (设\(A_x\)表示原数列中第 \(x\) 个数, \(F[x]\) 表示以第 \(x\) 个数结束的最长不降子序列的长度, \(s\), \(t\) 表示起点终点)
 第二问最大流, 对于\(A_i<A_j\)\(F_i+1==F_j\)\(i<j\) 的点对建 \(i\to j\), 对于\(F _x=1\)的点建\(s\to x\), 对于$F_x = ans1 $ (第一问答案)的点建 \(x\to t\), 求最大流.
 第三问将\(s\to 1\)\(n\to t\)的容量设为一个极大值, 再求最大流.
 
 细节见代码.
 

- 代码 -

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
 
const int N = 400 + 5;
const int M = 2e5 + 5;
const int inf = 0x3f3f3f3f;
 
int F[N], A[N];
int HD[N], CUR[N];
int NXT[M], FRM[M], TO[M], V[M];
int DIS[N];
int n, m, ans, sz, cnt, ss, tt;
queue<int> q;
 
void add(int x, int y) {
    TO[sz] = y; FRM[sz] = x; V[sz] = 1;
    NXT[sz] = HD[x]; HD[x] = sz++;
    TO[sz] = x; FRM[sz] = y; V[sz] = 0;
    NXT[sz] = HD[y]; HD[y] = sz++;
}
 
bool bfs() {
    memset(DIS, -1, sizeof (DIS));
    DIS[ss] = 0;
    q.push(ss);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = HD[u]; i != -1; i = NXT[i]) {
            int v = TO[i];
            if (DIS[v] < 0 && V[i]) {
                q.push(v);
                DIS[v] = DIS[u] + 1;
            }
        }
    }
    return DIS[tt] > 0;
}
 
 
int dfs(int x,int a) {
    if (x == tt) return a;
    int flow = 0, f;
    for (int& i = CUR[x]; i != -1; i = NXT[i]) {
        if (V[i] && DIS[TO[i]] == DIS[x] + 1)
            if (f = dfs(TO[i], min(a, V[i]))) {
                V[i] -= f;
                V[i^1] += f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
    }
    return flow;
}
 
int dinic() {
    int flow = 0;
    while (bfs()) {
        memcpy(CUR, HD, sizeof (HD));
        flow += dfs(ss, inf);
    }
    return flow;
}
 
int main() {
    memset(HD, -1, sizeof (HD));
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        F[i] = 1;
        for (int j = 1; j < i; ++j) {
            if (A[j] < A[i])
                F[i] = max(F[i], F[j] + 1);
        }
        ans = max(ans, F[i]);
    }
    printf("%d\n", ans);
    ss = 0, tt = n + 1;
    for (int i = 1; i <= n; ++i) {
        if (F[i] == 1) add(ss, i);
        if (F[i] == ans) add(i, tt);
        for (int j = 1; j < i; ++j) {
                if (A[j] < A[i] && F[j] + 1 == F[i])
                    add(j, i);
            }
    }
    printf("%d\n", dinic());
    for (int i = 0; i < sz; ++i) {
        if (TO[i] == 1) V[i] = inf;
        else if (FRM[i] == n) V[i] = inf;
        else V[i] = (i % 2) ^ 1; //更改以及初始化边容量
    }
    printf("%d\n", dinic());
    return 0;
}
posted @ 2017-08-22 19:41  lstttt  阅读(192)  评论(0)    收藏  举报