前言
我嘞个费用流啊,我勒个建模好题啊
题意
简述:
在一个 n × m n\times m n×m 的网格图内有一些水管,问能否拼成不漏水的形状。
题解
分析
看到方格图,按照套路,考虑对原图进行黑白染色。
然后看看这个图有什么用,考虑将源点连向所有黑点,所有白点连向汇点,然后直接跑最小费用最大流,如果 2 × 2\times 2× 最大流量 = = =接口数,那么解即为最小费用,否则无解。
因为每一个白点接口和每一个黑点接口匹配上,就可以产生 1 1 1 点贡献,所以总贡献因为接口总数的一半,否则就有接口匹配不上,就漏水了。
怎么建图呢?考虑拆点,将每一个点拆成上,下,左,右,中五个点,中点连向源点或汇点,其余四个点和异种颜色的这四类点匹配。
重中之重来了——怎么旋转。
以黑点为例(白点的边要反过来)
先考虑最简单的: 000 1 ( 2 ) 0001_{(2)} 0001(2)
如图:
考虑连一条红边,流量为 1 1 1,费用为 0 0 0,这是这个水管的基本数据。
那旋转呢?
考虑连蓝边,流量为 1 1 1,费用 > 0 >0 >0
如图:
蓝边第一个数为流量,第二个数为费用,这样我们就可以模拟旋转操作了。只需要计算出相应的费用即可。
再深入一点,我们用红边限制流量,用蓝边模拟旋转。
接下来是 T 型,如图:
这个各位读者可以思考一下为什么是连 3 3 3 条边,且费用为什么为那些数,最好模拟一下。
然后是 L 型,如图:
剩下的都差不多,不画了。
Code
参考的核心代码:
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define cou(i) cout<<fixed<<setprecision(i)
using namespace std;
const int N=2e3+1,M=2e6+1,inf=1e9;
int n,m,k,s,t,o,ans,mi_c,idx=1,cnt=0;
int dis[M],h[M],vis[M],head[M]