P4003 无限之环 题解

news/2025/3/22 14:47:47/文章来源:https://www.cnblogs.com/biyimouse/p/18786573

原题链接

超级有意思的网络流题!

先转化一下题目条件,要求棋盘中不存在漏水的地方,则对于每个格子的四个方向的管子必须要全部连上,这可以对应到网络流中的满流。接着由于我们要寻找最少操作次数,所以我们可以联想到费用流。

具体的建模挺巧妙地。

首先我们把格子按照黑白染色(这可以通过方格横纵坐标相加的奇偶性判断),接着将每个格子内部拆成上下左右中五个点,然后让源点连向黑格子的中点,白格子的中点连向汇点,容量为 \(\infty\),单位费用为 \(0\)

然后对于每个格子内部按照给出的水管形状,将中间点连向上下左右四个点,容量为 \(1\),单位费用为 \(0\)。由于相邻两个格子之间的流要可以互通,所以我们不妨将两个格子的相邻结点相连,比如左侧格子的右节点和右侧格子的左节点,容量为 \(1\),单位费用为 \(0\)

这样我们就把格子内的管子转化成了网络流中的边,就可以使用费用流了。

但我们还需要考虑如何处理格子内的管子旋转。我们可以将所有的水管类型分为五种,分别是没有管子(\(0\))、直线型管子(\(5, 10\))、\(1\) 型管子(\(1、2、4、8\)),\(L\) 型管子(\(3、6、12、9\))、\(T\) 型管子(\(7、14、13、11\))、十字型管子(\(15\))。容易发现没有管子和直线型管子根据题目都无法操作,十字型管子操作了没意义,所以我们只需考虑剩下三种。

  1. \(1\)

    我们先考虑指向上方的水管类型(其余方向的均可以通过添加偏移量进行转化,具体详见代码),它可以转一次到左和右、转两次到下,所以我们不妨分别从左、右向上连容量为 \(1\),单位费用为 \(1\) 的边,从下向上连容量为 \(1\),单位费用为 \(2\) 的边。

  2. \(L\)

    同样地我们只考虑指向上方和右方的水管类型,它转一次可以转化成左、上和右、下。可以发现这两种情况都只有一条边发生了改变,所以我们只需从左向右,从下向上连费用为 \(1\) 的边即可。此时你会发现转两下的情况已经可以通过同时进行前两中操作表示了。

  3. \(T\)

    我们直接给出连边方案,对于指向上、右、左的连边方案,我们从下到左、右分别连一条费用为 \(1\) 的边,再从下到上连费用为 \(2\) 的边即可。

我们在建图过程中记录一下格子内连向中点的边数,然后跑最小费用最大流。跑完后如果不满流就说明无解,否则输出最小费用。

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i <= (b); i ++)
#define fro(i, a, b) for (int i = (a); i >= b; i --)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define lowbit(x) (x & (-x))
#define initrand srand((unsigned)time(0))
#define random(x) ((LL)rand() * rand() % (x))
#define eb emplace_back
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
inline int read() {int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }return x * f;
}const int N = 20010, M = 200010;
int n, m, k, s, t, tmp, turn, tp;
int h[N], e[M], ne[M], w[M], f[M], idx;
int d[N], vis[N], pre[M], incf[N];
int maxflow, minc; 
queue<int> q;void add(int a, int b, int c, int d, int tp) {if (tp) swap(a, b); e[idx] = b, w[idx] = c, f[idx] = d, ne[idx] = h[a], h[a] = idx ++;e[idx] = a, w[idx] = 0, f[idx] = -d, ne[idx] = h[b], h[b] = idx ++;
}bool spfa() {memset(d, 0x3f, sizeof d); memset(vis, 0, sizeof vis);while (!q.empty()) q.pop();d[s] = 0, vis[s] = 1, incf[s] = 1 << 30; q.push(s);while (!q.empty()) {int u = q.front(); q.pop();vis[u] = 0;for (int i = h[u]; ~i; i = ne[i]) {int v = e[i];if (w[i] && d[v] > d[u] + f[i]) {d[v] = d[u] + f[i], pre[v] = i, incf[v] = min(incf[u], w[i]); if (!vis[v]) vis[v] = 1, q.push(v);}}}return d[t] != 0x3f3f3f3f;
}
void upd() {int u = t;while (u != s) {int p = pre[u];w[p] -= incf[t], w[p ^ 1] += incf[t];u = e[p ^ 1];}maxflow += incf[t]; minc += incf[t] * d[t];
}// 这就是前文所说的快捷方式
inline int self(int x) { return tmp * 4 + x; }
inline int U(int x) { return x + turn * tmp; }
inline int R(int x) { return x + (turn + 1 & 3) * tmp; }
inline int D(int x) { return x + (turn + 2 & 3) * tmp; }
inline int L(int x) { return x + (turn + 3 & 3) * tmp; }int main() {memset(h, -1, sizeof h);n = read(), m = read(); int upflow = 0;tmp = n * m, t = tmp * 5 + 1, k = 1;rep(i, 1, n) rep(j, 1, m) {int x = read(); tp = i + j & 1; turn = 0;if (tp) add(s, self(k), INF, 0, 0);else add(self(k), t, INF, 0, 0);if (i != 1) add(D(k - m), U(k), 1, 0, tp);if (j != 1) add(R(k - 1), L(k), 1, 0, tp);if (x & 1) add(U(k), self(k), 1, 0, tp), upflow ++;if (x & 2) add(R(k), self(k), 1, 0, tp), upflow ++;if (x & 4) add(D(k), self(k), 1, 0, tp), upflow ++;if (x & 8) add(L(k), self(k), 1, 0, tp), upflow ++;switch(x) {case 8: turn ++;case 4: turn ++;case 2: turn ++;case 1: add(R(k), U(k), 1, 1, tp);add(L(k), U(k), 1, 1, tp);add(D(k), U(k), 1, 2, tp);break;case 9: turn ++;case 12: turn ++;case 6: turn ++;case 3:add(D(k), U(k), 1, 1, tp);add(L(k), R(k), 1, 1, tp);break;case 13: turn ++;case 14: turn ++;case 7: turn ++;case 11: add(D(k), L(k), 1, 1, tp);add(D(k), R(k), 1, 1, tp);add(D(k), U(k), 1, 2, tp);break;}k ++;} while (spfa()) upd();printf("%d\n", maxflow == upflow / 2 ? minc : -1);return 0;
}

真神奇,也真难写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/903476.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20241227曹鹏泰 python1

课程:《Python 程序设计》 班级: 2412 姓名: 曹鹏泰 学号: 20241227 实验教师:王志强 实验日期:2025 年 3 月 12 日 必修/选修: 公选课 一、实验内容 熟悉 Python 开发环境; 练习 Python 运行、调试技能(编写书中的程序,并进行调试分析,要有过程); 编写程序…

ospfv3收到adv为全零的5类lsa,该怎么处理?

问题现象:ospfv3建立邻居后发现部分路由丢失原因:抓包查看时发现对端华为设备发送的5类LSA报文中ADV为全0,设备将LSA加到LSDB后,未将其加到边界路由表,导致下发路由中缺失部分路由 临时处理办法:下发边界路由时检查LSDB中是否存在ADV为全0的5类LSA,存在则查找LSDB,得到…

FristiLeaks_1

FristiLeaks_1.3 环境搭建 下载:https://download.vulnhub.com/fristileaks/FristiLeaks_1.3.ova 导入后将mac地址修改为:08:00:27:A5:A6:76信息收集 扫描主机ip ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:84:b2:cc, IPv4: 1…

绿联nas防火墙导致docker网络无法互通

问题描述设备:绿联nas dxp4800 系统:ugnas pro 绿联新系统在12月份更新后,原本用nginx代理的alist,青龙等服务全都连接不上,在ugnas系统防火墙设置如下:对外只通过80端口,其他docker服务都只能通过nginx反代访问,系统更新前一直都没问题。 问题排查 经过反复排查发现关…

20244119 实验一 《Python程序设计》 实验报告

课程:《Python程序设计》 班级: 2441 姓名: 霍彬斌 学号:20244109 实验教师:王志强 必修/选修: 公选课 一、实验内容 熟悉Pycharm等开发环境; 掌握基本的Python运行和调试技能; 掌握基本的Python编程技能。 二、实验过程及结果 1.熟悉Python开发环境; 本次实验使用pyc…

一步一步教你部署ktransformers,大内存单显卡用上Deepseek-R1

环境准备 硬件环境 CPU:intel四代至强及以上,AMD参考同时期产品 内存:800GB以上,内存性能越强越好,建议DDR5起步 显卡:Nvidia显卡,单卡显存至少24GB(用T4-16GB显卡实测会在加载模型过程中爆显存),nvidia compute capability至少8.0(CUDA GPUs - Compute Capability …

20244119实验一《Python程序设计》实验报告

课程:《Python程序设计》 班级: 2441 姓名: 霍彬斌 学号:20244109 实验教师:王志强 必修/选修: 公选课 一、实验内容 熟悉Pycharm等开发环境; 掌握基本的Python运行和调试技能; 掌握基本的Python编程技能。 二、实验过程及结果 1.熟悉Python开发环境; 本次实验使用pyc…

WebSocket系列 注册 @ServerEndpoint类失败

WebSocket系列—注册 @ServerEndpoint类失败 目录WebSocket系列—注册 @ServerEndpoint类失败一、问题背景二、寻找问题三、解决问题3.1、自己定义的切面3.2、外部框架的切面四、参考博客五、WebSocket系列地址 一、问题背景 博主最近分到后端主动推送报警业务,调研了一圈(轮…

实验1 C语言输入输出和简单程序编写补充

任务二:判断它能否构成三角形 #include <stdio.h> int main(){ double a, b, c; scanf_s("%lf%lf%lf", &a, &b, &c); if ((a + b > c) && (a + c > b) && (b + c > a)) printf("能构成三角…

ASE15N45-ASEMI智能家居专用ASE15N45

ASE15N45-ASEMI智能家居专用ASE15N45编辑:ll ASE15N45-ASEMI智能家居专用ASE15N45 型号:ASE15N45 品牌:ASEMI 封装:TO-220 批号:最新 最大漏源电流:15A 漏源击穿电压:450V RDS(ON)Max:0.38Ω 引脚数量:3 沟道类型:N沟道MOS管、中低压MOS管 漏电流:ua 特性:N沟道M…

什么是RabbitMQ入门

一.什么是RabbitMQ 中间件(Middleware)是处于操作系统和应用程序之间的软件,也有人认为它应该属于操作系统中的一部分。人们在使用中间件时,往往是一组中间件集成在一起,构成一个平台(包括开发平台和运行平台),但在这组中间件中必须要有一个通信中间件,即中间件=平台+…

使用BL0937 IC进行交流电源监控

一个简单的电路来监测交流电源,接线板可以插在任何地方,显示电压,电流和功率。交流电源监控是当今物联网相关应用中的一个惊人功能,例如智能风扇,开关和板。一些优秀的公司董事会在他们的产品中实施了这项技术,并持续监控供应的输出功率。在本地设备层面监控电源有其自身…