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