IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> P2766 Dinic -> 正文阅读

[数据结构与算法]P2766 Dinic

题意

传送门 P2766 最长不下降子序列问题

题解

最长不下降子序列的长度 DP 求解即可。 d p i dp_i dpi? 代表 i i i 为初始元素的最长不下降子序列长度。 d p i = max ? i < j , x i ≤ x j { d p j } + 1 dp_i = \max_{i<j,x_i\leq x_j} \{dp_j\}+1 dpi?=maxi<j,xi?xj??{dpj?}+1

对于第二问,由于子序列长度 l e n len len 是可达的最大长度,那么子序列第 k k k 个元素只可能是 d p i = l e n ? k + 1 dp_i=len-k+1 dpi?=len?k+1 的位置 i i i,否则,可以构造出更长的不下降子序列。那么可以根据分层图的思想建图。为了满足每个元素至多使用一次的约束,将元素 v v v 拆为入点 v i n v_{in} vin? 与出点 v o u t v_{out} vout? v i n → v o u t v_{in}\rightarrow v_{out} vin?vout? 连一条容量为 1 1 1 的边。

设源点汇点分别为 s , t s,t s,t,则对于 d p i = l e n dp_i = len dpi?=len 的节点 s → v i n s\rightarrow v_{in} svin?,对于 d p i = 1 dp_i = 1 dpi?=1 的节点 v o u t → t v_{out}\rightarrow t vout?t,其余节点 i i i 向可能为其所在子序列下一个元素的节点 j j j 连一条边。对于第二问而言,这些边的容量大于等于 1 1 1 即可。最大流即第二问答案。

对于第三问,首先去掉起始与结尾元素的限制,即对于 d p i = l e n dp_i = len dpi?=len d p i = 1 dp_i=1 dpi?=1 的节点,在第二问基础上去除使用次数的限制,即 i i n → i o u t i_{in}\rightarrow i_{out} iin?iout? 连一条容量为 ∞ \infty 的边。对于元素 x i x_i xi?,其所在不下降子序列中的下一个位置的可能元素 x j x_j xj? 必然互不相同,否则可以构造出更长的不下降子序列。那么只需要使 i o u t → j i n i_{out}\rightarrow j_{in} iout?jin? 边的容量设置为 1 1 1。跑 Dinic ,最大流即第三问答案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int MAXN = 505, MAXV = MAXN * 2, INF = 0x3f3f3f3f;
int N, V;
struct edge
{
    int to, cap, rev;
};
vector<edge> G[MAXV];
int iter[MAXV], level[MAXV];

void add_edge(int from, int to, int cap)
{
    G[from].pb({to, cap, G[to].size()});
    G[to].pb({from, 0, G[from].size() - 1});
}

void bfs(int s)
{
    for (int v = 0; v < V; ++v)
        level[v] = -1;
    queue<int> q;
    level[s] = 0;
    q.push(s);
    while (q.size())
    {
        int v = q.front();
        q.pop();
        for (auto &e : G[v])
            if (e.cap > 0 && level[e.to] == -1)
                level[e.to] = level[v] + 1, q.push(e.to);
    }
}

int dfs(int v, int t, int f)
{
    if (v == t)
        return f;
    for (int &i = iter[v]; i < G[v].size(); ++i)
    {
        auto &e = G[v][i];
        if (e.cap > 0 && level[e.to] > level[v])
        {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d > 0)
            {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s, int t)
{
    int flow = 0;
    for (;;)
    {
        bfs(s);
        if (level[t] == -1)
            return flow;
        for (int v = 0; v < V; ++v)
            iter[v] = 0;
        int f;
        while ((f = dfs(s, t, INF)) > 0)
            flow += f;
    }
}

int a[MAXN], dp[MAXN];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N;
    for (int i = 0; i < N; ++i)
        cin >> a[i];
    dp[N] = 0, a[N] = INF;
    int len = 0, cnt = 0;
    for (int i = N - 1; i >= 0; --i)
    {
        for (int j = i + 1; j <= N; ++j)
            if (a[i] <= a[j])
                dp[i] = max(dp[i], dp[j] + 1);
        if (dp[i] > len)
            len = dp[i], cnt = 1;
        else if (dp[i] == len)
            ++cnt;
    }
    cout << len << '\n';

    int s = 2 * N, t = s + 1;
    V = t + 1;
    for (int i = 0; i < N; ++i)
    {
        if (dp[i] == len)
            add_edge(s, i, INF);
        if (dp[i] == 1)
            add_edge(N + i, t, INF);
        add_edge(i, N + i, 1);
        for (int j = i + 1; j < N; ++j)
            if (a[i] <= a[j] && dp[i] == dp[j] + 1)
                add_edge(N + i, j, 1);
    }
    int flow = max_flow(s, t);
    cout << flow << '\n';

    if (len == 1)
    {
        cout << cnt << '\n';
        return 0;
    }
    for (int i = 0; i < N; ++i)
    {
        if (dp[i] == len)
            add_edge(i, N + i, INF);
        if (dp[i] == 1)
            add_edge(i, N + i, INF);
    }
    flow += max_flow(s, t);
    cout << flow << '\n';
    return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:48:42  更:2022-03-24 00:50:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 1:00:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码