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 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> P4003 无限之环 -> 正文阅读

[C++知识库]P4003 无限之环

题面自己看吧。。。

std

对于这种毒瘤的最小费用匹配问题,一般考虑网络费用流。

对于每个水管的每一个支管,有且仅有一个其它方格上的水管的其中一个支管与其相连,这样就不会漏水了,也就是一个水管的每个支管容量只能为 1 1 1,且都要满流。

由于我们要用网络流,又考虑到只有相邻的两个水管又可能产生流量,于是考虑将图黑白染色。

这样黑点只能连向白点,白点只能连向黑点。

然后将一个方格拆成 5 5 5 个点,分别表示上下左右中。

模型建立

s s s 向白点的中点连一条容量为支管数量,费用为 0 0 0 的边。

黑点的中点向 t t t 连一条容量为支管数量,费用为 0 0 0 的边。

根据支管情况向四周连容量为 1 1 1,费用为 0 0 0 的边。

然后分水管的情况讨论:

1

上点分别向左,右点向一条容量为 1 1 1,费用为 1 1 1 的边(转 90 90 90 度)。

上点向下点连向一条容量为 1 1 1,费用为 2 2 2 的边(转 180 180 180 度)。

2

由于不用旋转,那么只需让中点分别向上、下点连一条容量为 1 1 1,费用为 0 0 0 的边(上面说过了)。

3

顺时针转 90 90 90 度,会变成这样:

这相当于原来的上点变成了下点,右点不变,那么让上点向下点连一条容量为 1 1 1,费用为 1 1 1 的边即可。

逆时针转 90 90 90 度同理,让右点向左点连一条容量为 1 1 1,费用为 1 1 1 的边即可。

180 180 180 度,会变成这样:

这相当于,你将前面说的两条边一起用了。

4

顺时针转 90 90 90 度,会变成这样:

这相当于上、右点不变,左点变成了下点,于是让左点向下点连一条容量为 1 1 1,费用为 1 1 1 的边即可。

逆时针转 90 90 90 度同理,让右点向下点连一条容量为 1 1 1,费用为 1 1 1 的边即可。

180 180 180 度,会变成这样:

这相当于左、右点不变,上点变成了下点,于是让上点向下点连一条容量为 1 1 1,费用为 2 2 2 的边即可。

5

由于这转了相当于没转,那么不管他。

231ms?/?1.71MB?/?7.49KB?C++20?O2 \text{231ms / 1.71MB / 7.49KB C++20 O2} 231ms?/?1.71MB?/?7.49KB?C++20?O2

#include <bits/stdc++.h>

using namespace std;

inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

inline void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

typedef int tp;

const int _ = 6e4 + 10, inf = 947483647;

int n, m, s, t, lv[_], cur[_];

tp maxflow, mincost;

int tot = 1, head[_], to[_ << 1], nxt[_ << 1];

tp dis[_], w[_ << 1], fl[_ << 1];

inline void add(int u, int v, tp dis, tp c)
{
    to[++tot] = v;
    nxt[tot] = head[u];
    fl[tot] = dis;
    w[tot] = c;
    head[u] = tot;
}

inline void Add(int u, int v, tp dis, tp c)
{
    add(u, v, dis, c);
    add(v, u, 0, -c);
}

inline bool bfs()
{
    memset(lv, 0, sizeof(lv));
    for (int i = 0; i < _; ++i)
        dis[i] = inf;
    lv[s] = 1;
    dis[s] = 0;
    memcpy(cur, head, sizeof(head));
    queue<int> q;
    q.push(s);
    while (!q.empty())
    {
        int p = q.front();
        q.pop();
        lv[p] = 0;
        for (int eg = head[p]; eg; eg = nxt[eg])
        {
            int v = to[eg];
            tp vol = fl[eg];
            if (vol > 0 && dis[v] > dis[p] + w[eg])
            {
                dis[v] = dis[p] + w[eg];
                if (!lv[v])
                {
                    q.push(v);
                    lv[v] = 1;
                }
            }
        }
    }
    return dis[t] != inf;
}

tp dfs(int p = s, tp flow = inf)
{
    if (p == t)
        return flow;
    lv[p] = 1;
    tp rmn = flow;
    for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
    {
        cur[p] = eg;
        int v = to[eg];
        tp vol = fl[eg];
        if (vol > 0 && !lv[v] && dis[v] == dis[p] + w[eg])
        {
            tp c = dfs(v, min(vol, rmn));
            rmn -= c;
            fl[eg] -= c;
            fl[eg ^ 1] += c;
        }
    }
    lv[p] = 0;
    return flow - rmn;
}

inline void dinic()
{
    while (bfs())
    {
        tp flow = dfs();
        maxflow += flow;
        mincost += dis[t] * flow;
    }
}

inline int id(int x, int y, int num)
{
    return (x - 1) * m + y + num * n * m;
}

int sum;

const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}, cross[] = {3, 4, 1, 2};

inline void build(int x, int y, int num)
{
    if ((x + y) & 1)
    {
        Add(s, id(x, y, 0), 1 << 30, 0);
        for (int i = 0; i < 4; ++i)
        {
            int xx = x + dx[i], yy = y + dy[i];
            if (xx <= 0 || xx > n || yy <= 0 || yy > m)
                continue;
            Add(id(x, y, i + 1), id(xx, yy, cross[i]), 1, 0);
        }
        for (int i = 0; i < 4; ++i)
            if (num & (1 << i))
            {
                Add(id(x, y, 0), id(x, y, i + 1), 1, 0);
                ++sum;
            }
        switch (num)
        {
        case 1:
            Add(id(x, y, 1), id(x, y, 2), 1, 1);
            Add(id(x, y, 1), id(x, y, 3), 1, 2);
            Add(id(x, y, 1), id(x, y, 4), 1, 1);
            break;
        case 2:
            Add(id(x, y, 2), id(x, y, 1), 1, 1);
            Add(id(x, y, 2), id(x, y, 3), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 2);
            break;
        case 4:
            Add(id(x, y, 3), id(x, y, 1), 1, 2);
            Add(id(x, y, 3), id(x, y, 2), 1, 1);
            Add(id(x, y, 3), id(x, y, 4), 1, 1);
            break;
        case 8:
            Add(id(x, y, 4), id(x, y, 1), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 2);
            Add(id(x, y, 4), id(x, y, 3), 1, 1);
            break;
        case 3:
            Add(id(x, y, 1), id(x, y, 3), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 1);
            break;
        case 6:
            Add(id(x, y, 3), id(x, y, 1), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 1);
            break;
        case 9:
            Add(id(x, y, 1), id(x, y, 3), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 1);
            break;
        case 12:
            Add(id(x, y, 3), id(x, y, 1), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 1);
            break;
        case 7:
            Add(id(x, y, 1), id(x, y, 4), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 2);
            Add(id(x, y, 3), id(x, y, 4), 1, 1);
            break;
        case 11:
            Add(id(x, y, 1), id(x, y, 3), 1, 2);
            Add(id(x, y, 2), id(x, y, 3), 1, 1);
            Add(id(x, y, 4), id(x, y, 3), 1, 1);
            break;
        case 13:
            Add(id(x, y, 1), id(x, y, 2), 1, 1);
            Add(id(x, y, 3), id(x, y, 2), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 2);
            break;
        case 14:
            Add(id(x, y, 2), id(x, y, 1), 1, 1);
            Add(id(x, y, 3), id(x, y, 1), 1, 2);
            Add(id(x, y, 4), id(x, y, 1), 1, 1);
            break;
        }
    }
    else
    {
        Add(id(x, y, 0), t, 1 << 30, 0);
        for (int i = 0; i < 4; ++i)
            if (num & (1 << i))
            {
                Add(id(x, y, i + 1), id(x, y, 0), 1, 0);
                ++sum;
            }
        switch (num)
        {
        case 1:
            Add(id(x, y, 2), id(x, y, 1), 1, 1);
            Add(id(x, y, 3), id(x, y, 1), 1, 2);
            Add(id(x, y, 4), id(x, y, 1), 1, 1);
            break;
        case 2:
            Add(id(x, y, 1), id(x, y, 2), 1, 1);
            Add(id(x, y, 3), id(x, y, 2), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 2);
            break;
        case 4:
            Add(id(x, y, 1), id(x, y, 3), 1, 2);
            Add(id(x, y, 2), id(x, y, 3), 1, 1);
            Add(id(x, y, 4), id(x, y, 3), 1, 1);
            break;
        case 8:
            Add(id(x, y, 1), id(x, y, 4), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 2);
            Add(id(x, y, 3), id(x, y, 4), 1, 1);
            break;
        case 3:
            Add(id(x, y, 3), id(x, y, 1), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 1);
            break;
        case 6:
            Add(id(x, y, 1), id(x, y, 3), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 1);
            break;
        case 9:
            Add(id(x, y, 3), id(x, y, 1), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 1);
            break;
        case 12:
            Add(id(x, y, 1), id(x, y, 3), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 1);
            break;
        case 7:
            Add(id(x, y, 4), id(x, y, 1), 1, 1);
            Add(id(x, y, 4), id(x, y, 2), 1, 2);
            Add(id(x, y, 4), id(x, y, 3), 1, 1);
            break;
        case 11:
            Add(id(x, y, 3), id(x, y, 1), 1, 2);
            Add(id(x, y, 3), id(x, y, 2), 1, 1);
            Add(id(x, y, 3), id(x, y, 4), 1, 1);
            break;
        case 13:
            Add(id(x, y, 2), id(x, y, 1), 1, 1);
            Add(id(x, y, 2), id(x, y, 3), 1, 1);
            Add(id(x, y, 2), id(x, y, 4), 1, 2);
            break;
        case 14:
            Add(id(x, y, 1), id(x, y, 2), 1, 1);
            Add(id(x, y, 1), id(x, y, 3), 1, 2);
            Add(id(x, y, 1), id(x, y, 4), 1, 1);
            break;
        }
    }
}

signed main()
{
    n = read(), m = read();
    s = 0, t = _ - 1;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
        {
            int p = read();
            build(i, j, p);
        }
    dinic();
    write(maxflow * 2 == sum ? mincost : -1);
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:43:52  更:2022-03-06 12:44:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:38:34-

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