码迷,mamicode.com
首页 > 其他好文 > 详细

网络流 24 题 最长递增子序列

时间:2020-06-03 00:32:19      阅读:44      评论:0      收藏:0      [点我收藏+]

标签:space   ++i   href   tps   opera   const   序列   ++   选择   

链接

题解

  • 首先对序列做一个简单$dp$求出以每个位置为末尾的最长上升子序列长度$dp_i$,求出最长上升子序列长度$k$,然后考虑如何建图
  • 对于每个$dp_i=1$的位置从源点连一条流量为1的边
  • 对于每个$dp_i=k$的位置向汇点连一条流量为1的边
  • 对于每个位置$i$,向满足$j>i,dp_j=dp_i+1,a_j>a_i$的位置连一条流量为1的边
  • 但是这样每个点可能会被选择多次,所以可以对每个位置进行拆点,拆为入点$i$和出点$i+n$入点连入边,出点连出边,入点和出点之间连接流量为1的边这样就能保证每个点只被选择一次
  • 对于第3个问题,只需要将1和n与源点和汇点的流量以及它们的入点和出点之间的流量改为无穷大
  • 建完图跑最大流即可
  • 注意特判序列是单调递减的情况
查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
ll qpow(ll a, ll b)
{
    ll res = 1;
    for (; b; b >>= 1)
    {
        if (b & 1)
            res = res * a % mod;
        a = a * a % mod;
    }
    return res;
}
struct graph
{
    int head[maxn], nxt[maxn << 1], to[maxn << 1], w[maxn << 1], sz;
    void init()
    {
        memset(head, -1, sizeof(head));
        sz = 0;
    }
    graph() { init(); }
    void push(int a, int b, int c) { nxt[sz] = head[a], to[sz] = b, w[sz] = c, head[a] = sz++; }
    int &operator[](const int a) { return to[a]; }
} g;
int d[1005], now[1005];
int s, t;
bool bfs()
{
    memset(d, 0, sizeof(d));
    queue<int> q;
    q.push(s);
    d[s] = 1;
    now[s] = g.head[s];
    while (!q.empty())
    {
        int x = q.front();
        q.pop();
        for (int i = g.head[x]; ~i; i = g.nxt[i])
        {
            if (!d[g[i]] && g.w[i])
            {
                d[g[i]] = d[x] + 1;
                now[g[i]] = g.head[g[i]];
                q.push(g[i]);
                if (g[i] == t)
                    return 1;
            }
        }
    }
    return 0;
}
int dinic(int x, int flow)
{
    if (x == t)
        return flow;
    int res = flow, i, k;
    for (i = now[x]; ~i && res; i = g.nxt[i])
    {
        if (d[g[i]] == d[x] + 1 && g.w[i])
        {
            k = dinic(g[i], min(res, g.w[i]));
            if (!k)
                d[g[i]] = 0;
            res -= k;
            g.w[i] -= k;
            g.w[i ^ 1] += k;
        }
    }
    now[x] = i;
    return flow - res;
}
int dp[505], a[505];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("simple.in", "r", stdin);
    freopen("simple.out", "w", stdout);
#endif
    int n, k = 0;
    scanf("%d", &n);
    s = 0, t = n * 2 + 1;
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
    {
        dp[i] = 1;
        for (int j = 1; j < i; ++j)
        {
            if (a[i] >= a[j])
            {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        k = max(k, dp[i]);
    }
    if (k == 1)
    {
        printf("%d\n%d\n%d\n", k, n, n);
        return 0;
    }
    for (int i = 1; i <= n; ++i)
    {
        g.push(i, i + n, 1), g.push(i + n, i, 0);
        if (dp[i] == 1)
        {
            g.push(s, i, 1), g.push(i, s, 0);
        }
        if (dp[i] == k)
        {
            g.push(i + n, t, 1), g.push(t, i + n, 0);
        }
        for (int j = 1; j < i; ++j)
        {
            if (a[i] >= a[j] && dp[i] == dp[j] + 1)
            {
                g.push(n + j, i, 1), g.push(i, n + j, 0);
            }
        }
    }
    int flow, ans2 = 0;
    while (bfs())
    {
        while (flow = dinic(s, 1e9))
            ans2 += flow;
    }
    g.init();
    for (int i = 1; i <= n; ++i)
    {
        int w = (i == 1 || i == n) ? 1e9 : 1;
        g.push(i, i + n, w), g.push(i + n, i, 0);
        if (dp[i] == 1)
        {
            g.push(s, i, w), g.push(i, s, 0);
        }
        if (dp[i] == k)
        {
            g.push(i + n, t, w), g.push(t, i + n, 0);
        }
        for (int j = 1; j < i; ++j)
        {
            if (a[i] >= a[j] && dp[i] == dp[j] + 1)
            {
                g.push(n + j, i, 1), g.push(i, n + j, 0);
            }
        }
    }
    int f, ans3 = 0;
    while (bfs())
    {
        while (f = dinic(s, 1e9))
            ans3 += f;
    }
    cout << k << endl
         << ans2 << endl
         << ans3 << endl;
    return 0;
}

网络流 24 题 最长递增子序列

标签:space   ++i   href   tps   opera   const   序列   ++   选择   

原文地址:https://www.cnblogs.com/aaddvvaanntteezz/p/13034756.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!