[洛谷P1129][ZJOI2007]矩阵游戏

题目大意:矩阵游戏在一个$N \times N$的方阵进行。每次可以交换矩阵任意两行或两列,要求若干次操作后使得主对角线上的元素均为$1$。判断是否有解

题解:观察题目,可以发现是一个二分图匹配问题,即要求把行和列进行匹配,一个$1$就是一条边,若最大匹配为$n$就有解,否则无解

卡点:1.最开始题意理解错

 

C++ Code:

#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 410;
const int inf = 0x3f3f3f3f;
int Tim, n, a;
int d[maxn], q[maxn], h, t;
int st, ed;
int head[maxn], cnt = 2, head_[maxn];
struct Edge {
	int to, nxt, w;
} e[210 * 210 << 1];
void add(int a, int b, int c) {
	e[cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
	e[cnt ^ 1] = (Edge) {a, head[b], 0}; head[b] = cnt ^ 1;
	cnt += 2;
}
inline int min(int a, int b) {if (a < b) return a; else return b;}
inline bool bfs() {
	memset(d, 0, sizeof d);
	memcpy(head, head_, sizeof head_);
	d[q[h = t = 0] = st] = 1;
	int u, v;
	while (h <= t) {
		u = q[h++];
		if (u == ed) return true;
		for (register int i = head[u]; i; i = e[i].nxt) {
			v = e[i].to;
			if (!d[v] && e[i].w) {
				d[v] = d[u] + 1;
				q[++t] = v;
			}
		}
	}
	return d[ed];
}
inline int dfs(int x, int low) {
	if (x == ed || !low) return low;
	int res = 0, w, v;
	for (register int &i = head[x]; i; i = e[i].nxt) {
		v = e[i].to;
		if (d[x] + 1 == d[v] && e[i].w) {
			w = dfs(v, min(low - res, e[i].w));
			e[i].w -= w;
			e[i ^ 1].w += w;
			res += w;
			if (res == low) return res;
		}
	}
	if (!res) d[x] = -1;
	return res;
}
int dinic(int n) {
	int ans = 0;
	memcpy(head_, head, sizeof head_);
	while (bfs()) ans += dfs(st, inf);
	if (ans == n) puts("Yes");
	else puts("No");
}
int main() {
	scanf("%d", &Tim);
	while (Tim--) {
		scanf("%d", &n);
		st = 0, ed = n << 1 | 1;
		for (int i = 1; i <= n; i++) {
			add(st, i, 1);
			add(i + n, ed, 1);
			for (int  j = 1; j <= n; j++) {
				scanf("%d", &a);
				if (a) {
					add(i, j + n, 1);
				}
			}
		}
		dinic(n);
		if (Tim) {
			memset(head, 0, sizeof head);
			cnt = 2;
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/9395192.html