题目大意:矩阵游戏在一个$N imes 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;
}