矩阵游戏

前言

我太菜了。。不得不看 TJ ,由于自己的 SB 誓言,我又来写 TJ 了。

蓝题我都要看 TJ, 我好菜啊,提前 AFO 吧

题解

题面

我们可以研究一个样例

.in

1
3
1 0 0
0 1 1
1 0 0

.out

No

我们做出这个操作,当 a [ i ] [ j ] = 1 a[i][j] = 1 a[i][j]=1 时,在二元组边集 E E E 中加入一个元素 ( i , j ) (i, j) (i,j),如图。

:左边的表示行,右边的表示列。

若交换行

引理一:行的交换不会改变最大匹配数

若我们此时将行1和2的编号交换,我们会发现图又变成了原图,所以我们可以把行的交换理解成行编号的交换,所以不会改变最大匹配数。

引理二:当最大匹配数等于 n n n 时,即匹配成功

而目标图像要求行 i i i和列 i i i匹配,而我们可以利用交换编号使其成为任意一个只要求点与点一一匹配的图像。

所以:

由引理一,我们的最大匹配数固定。再由引理二可知:

若初始图的最大匹配数不为 n n n,则无论怎么交换都不会变换成目标图像。

若初始图的最大匹配数为 n n n,则一定能变成目标图像。

若交换列

同理,根据图分析易得和交换行一样的结论

参考代码

#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

// #define int long long
#define LL long long

template <typename T> int read (T &x) {x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return 1;}
template <typename T> void write (T x) {if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxn = 200;

int t, n;

int len, Head[Maxn * 2 + 5];
struct edge {
	int to, Next;
}e[Maxn * Maxn * 2 + 5];
void add (int x, int y) {
	e[++len].to = y;
	e[len].Next = Head[x];
	Head[x] = len;
}

int match[Maxn * 2 + 5];
bool vis[Maxn * 2 + 5];
bool Edmonds (int u) {
	for (int i = Head[u]; i; i = e[i].Next) {
		int v = e[i].to;
		if (vis[v] == 1) continue;
		vis[v] = 1;
		if (match[v] == 0 || Edmonds (match[v]) == 1) {
			match[v] = u;
			return 1;
		}
	}
	return 0;
}

signed main () {
	read (t);
	while (t--) {
		len = 0;
		memset (match, 0, sizeof match);
		memset (Head, 0, sizeof Head);
		
		read (n);
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				int x; read (x);
				if (x == 1) {
					add (i, j + n);
					add (j + n, i);
				}
			}
		}
		int ans = 0;
		for (int i = 1; i <= n; i++) {
			memset (vis, 0, sizeof vis);
			if (Edmonds (i)) {
				ans++;
			}
		}
		if (ans == n) {
			printf ("Yes\n");
		}
		else {
			printf ("No\n");
		}
	}
	return 0;
}
posted @ 2021-03-13 13:51  C2022lihan  阅读(67)  评论(0编辑  收藏  举报