P4003 无限之环 题解

P4003 无限之环 题解

首先这个网格图就说明了一些问题。一般地,网格图主要的解决方法是 dp(尤其是插头 dp)。但是这个题里需要解决的只有相邻两个格子之间的相邻性问题,于是采取网格图另一个常见的思路:二分图染色。于是将这个网格图黑白染色,将一个格子的四壁拆成四个点,相邻的壁之间连边。这样就是一个二分图的模型了。

然后考虑 SB 的旋转操作。考虑这样建模的实质是什么。事实上网络的流量就是水管的指向,于是改变水管的指向就是要改变流量的转移。考虑能否在四壁之间相互转移,注意到除了直线型的都可以表示,然后发现直线不能转移,然后这题就做完了。

代码:

#include <bits/stdc++.h>
#define N 100005
#define M 2000005
#define inf 0x3f3f3f3f
#define pii pair<int, int>
#define mk make_pair
using namespace std;
int n, m;
struct Dinic {
	int n, s, t;
	struct Node {
		int to, nxt, fl, dis;
	} e[M];
	int head[N], cnt = 1;
	void add(int u, int v, int w = 0, int f = 1) {
		e[++cnt].to = v;
		e[cnt].fl = f;
		e[cnt].dis = w;
		e[cnt].nxt = head[u];
		head[u] = cnt;
		e[++cnt].to = u;
		e[cnt].fl = 0;
		e[cnt].dis = -w;
		e[cnt].nxt = head[v];
		head[v] = cnt;
	}
	int dis[N], inr[N];
	int pre[N];
	bool vis[N];
	int SPFA() {
		for (int i = 1; i <= n; i++) dis[i] = inf;
		queue<int>q;
		q.push(s);
		dis[s] = 0;
		inr[s] = inf;
		while (q.size()) {
			int x = q.front();
			q.pop();
			vis[x] = 0;
			for (int i = head[x]; i; i = e[i].nxt) {
				int y = e[i].to;
				if (e[i].fl > 0 && dis[y] > dis[x] + e[i].dis) {
					dis[y] = dis[x] + e[i].dis;
					pre[y] = i;
					inr[y] = min(inr[x], e[i].fl);
					if (!vis[y]) {
						vis[y] = 1;
						q.push(y);
					}
				}
			}
		}
		return dis[t] < inf;
	}
	pii MCMF() {
		int fl = 0, cost = 0;
		while (SPFA()) {
			fl += inr[t];
			cost += inr[t] * dis[t];
			int i;
			for (int x = t; x != s; x = e[i ^ 1].to) {
				i = pre[x];
				e[i].fl -= inr[t];
				e[i ^ 1].fl += inr[t];
			}
		}
		return mk(fl, cost);
	}
} dc;
int gt(int x, int y) {
	return (x - 1) * m + y - 1;
} 
int up(int x, int y) {
	return (gt(x, y) << 2) | 1;
}
int rg(int x, int y) {
	return (gt(x, y) << 2) + 2;
}
int dn(int x, int y) {
	return (gt(x, y) << 2) + 3;
}
int lf(int x, int y) {
	return (gt(x, y) << 2) + 4;
}
#define add dc.add
#define s dc.s
#define t dc.t
int chk(int x, int y) {
	return 1 <= x && x <= n && 1 <= y && y <= m;
}
int sum;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	s = ((n * m) << 2) + 1, t = dc.n = s + 1;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			int x;
			cin >> x;
			sum += __builtin_popcount(x);
			int u = up(i, j), d = dn(i, j), l = lf(i, j), r = rg(i, j);
			if ((i + j) & 1) {
				if (chk(i - 1, j)) add(u, dn(i - 1, j));
				if (chk(i + 1, j)) add(d, up(i + 1, j));
				if (chk(i, j - 1)) add(l, rg(i, j - 1));
				if (chk(i, j + 1)) add(r, lf(i, j + 1));
				if (x == 1) {
					add(s, u);
					add(u, l, 1);
					add(u, r, 1);
					add(u, d, 2);
				}
				else if(x == 2) {
					add(s, r);
					add(r, u, 1);
					add(r, d, 1);
					add(r, l, 2);
				}
				else if(x == 4) {
					add(s, d);
					add(d, l, 1);
					add(d, r, 1);
					add(d, u, 2);
				}
				else if(x == 8) {
					add(s, l);
					add(l, u, 1);
					add(l, d, 1);
					add(l, r, 2);
				}
				else if(x == 5) {
					add(s, u);
					add(s, d);
				}
				else if(x == 10) {
					add(s, l);
					add(s, r);
				}
				else if(x == 3) {
					add(s, u);
					add(s, r);
					add(u, d, 1);
					add(r, l, 1); 
				}
				else if(x == 9) {
					add(s, u);
					add(s, l);
					add(u, d, 1);
					add(l, r, 1);
				}
				else if(x == 6) {
					add(s, d);
					add(s, r);
					add(d, u, 1);
					add(r, l, 1);
				}
				else if(x == 12) {
					add(s, d);
					add(s, l);
					add(d, u, 1);
					add(l, r, 1);
				}
				else if(x == 11) {
					add(s, u);
					add(s, l);
					add(s, r);
					add(l, d, 1);
					add(r, d, 1);
					add(u, d, 2);
				}
				else if(x == 14) {
					add(s, d);
					add(s, l);
					add(s, r);
					add(l, u, 1);
					add(r, u, 1);
					add(d, u, 2);
				}
				else if(x == 13) {
					add(s, l);
					add(s, u);
					add(s, d);
					add(u, r, 1);
					add(d, r, 1);
					add(l, r, 2);
				}
				else if(x == 7) {
					add(s, r);
					add(s, u);
					add(s, d);
					add(u, l, 1);
					add(d, l, 1);
					add(r, l, 2);
				}
				else if(x == 15) {
					add(s, u);
					add(s, d);
					add(s, l);
					add(s, r);
				}
			}
			else {
				if (x == 1) {
					add(u, t);
					add(l, u, 1);
					add(r, u, 1);
					add(d, u, 2);
				}
				else if(x == 2) {
					add(r, t);
					add(u, r, 1);
					add(d, r, 1);
					add(l, r, 2);
				}
				else if(x == 4) {
					add(d, t);
					add(l, d, 1);
					add(r, d, 1);
					add(u, d, 2);
				}
				else if(x == 8) {
					add(l, t);
					add(u, l, 1);
					add(d, l, 1);
					add(r, l, 2);
				}
				else if(x == 5) {
					add(u, t);
					add(d, t);
				}
				else if(x == 10) {
					add(l, t);
					add(r, t);
				}
				else if(x == 3) {
					add(u, t);
					add(r, t);
					add(d, u, 1);
					add(l, r, 1);
				}
				else if(x == 9) {
					add(u, t);
					add(l, t);
					add(d, u, 1);
					add(r, l, 1);
				}
				else if(x == 6) {
					add(d, t);
					add(r, t);
					add(u, d, 1);
					add(l, r, 1);
				}
				else if(x == 12) {
					add(d, t);
					add(l, t);
					add(u, d, 1);
					add(r, l, 1);
				}
				else if(x == 11) {
					add(u, t);
					add(l, t);
					add(r, t);
					add(d, l, 1);
					add(d, r, 1);
					add(d, u, 2);
				}
				else if(x == 14) {
					add(d, t);
					add(l, t);
					add(r, t);
					add(u, l, 1);
					add(u, r, 1);
					add(u, d, 2);
				}
				else if(x == 13) {
					add(l, t);
					add(u, t);
					add(d, t);
					add(r, u, 1);
					add(r, d, 1);
					add(r, l, 2);
				}
				else if(x == 7) {
					add(r, t);
					add(u, t);
					add(d, t);
					add(l, u, 1);
					add(l, d, 1);
					add(l, r, 2);
				}
				else if(x == 15) {
					add(u, t);
					add(d, t);
					add(l, t);
					add(r, t);
				}
			}
		}
	pii ans = dc.MCMF();
	if ((ans.first << 1) != sum) cout << "-1\n";
	else cout << ans.second << "\n";
	return 0;
}
posted @   长安19路  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示