这道题如果不看题解,我是绝对想不到二分图匹配的。
咱们先不想二分图匹配的事,先想想什么状态是有解的:只要每一行都有一个黑块,且每一个黑块都在不同的一列,那么一定有解。因为即使这些黑块不在主对角线上,我们也可以通过交换行(列)来达到这个最终状态,这就像不断交换两个数来给一个序列排序一样。
然后考虑建图,每一行作为一个节点,为二分图的左部;每一列也作为一个节点,作为图的右部。如果(i, j)为黑,就给(i, j)连一条边。因为交换任意两行(列)是不会改变图的,可以这么想:每一行的编号不是绝对的,而是最最开始的编号,那么如果把1和3行交换,图上就是把节点1以及他所连的边挪到了3的位置上,3又挪到了1的位置上。
最后只要判断匹配数是否等于n即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 405; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 26 if(last == '-') ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) x = -x, putchar('-'); 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + '0'); 34 } 35 36 int t; 37 38 struct Edge 39 { 40 int from, to, cap, flow; 41 }; 42 vector<Edge> edges; 43 vector<int> G[maxn]; 44 void addEdge(int from, int to) 45 { 46 edges.push_back((Edge){from, to, 1, 0}); 47 edges.push_back((Edge){to, from, 0, 0}); 48 int sz = edges.size(); 49 G[from].push_back(sz - 2); 50 G[to].push_back(sz - 1); 51 } 52 53 void init() 54 { 55 edges.clear(); 56 for(int i = 0; i < maxn; ++i) G[i].clear(); 57 } 58 59 int dis[maxn]; 60 bool bfs() 61 { 62 Mem(dis); dis[0] = 1; 63 queue<int> q; q.push(0); 64 while(!q.empty()) 65 { 66 int now = q.front(); q.pop(); 67 for(int i = 0; i < (int)G[now].size(); ++i) 68 { 69 Edge& e = edges[G[now][i]]; 70 if(!dis[e.to] && e.cap > e.flow) 71 { 72 dis[e.to] = dis[now] + 1; 73 q.push(e.to); 74 } 75 } 76 } 77 return dis[t]; 78 } 79 int cur[maxn]; 80 int dfs(int now, int res) 81 { 82 if(now == t || res == 0) return res; 83 int flow = 0, f; 84 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 85 { 86 Edge& e = edges[G[now][i]]; 87 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0) 88 { 89 e.flow += f; 90 edges[G[now][i] ^ 1].flow -= f; 91 flow += f; 92 res -= f; 93 if(res == 0) break; 94 } 95 } 96 return flow; 97 } 98 99 int maxflow() 100 { 101 int flow = 0; 102 while(bfs()) 103 { 104 Mem(cur); 105 flow += dfs(0, INF); 106 } 107 return flow; 108 } 109 110 int main() 111 { 112 int T = read(); 113 while(T--) 114 { 115 init(); 116 int n = read(); t = n + n + 1; 117 for(int i = 1; i <= n; ++i) 118 { 119 addEdge(0, i); addEdge(i + n, t); 120 for(int j = 1; j <= n; ++j) if(read()) addEdge(i, j + n); 121 } 122 printf("%s\n", maxflow() == n ? "Yes" : "No"); 123 } 124 return 0; 125 }View Code