传送门 : https://ac.nowcoder.com/acm/contest/1063/C
棋子两两冲突,放最多的棋子。
把冲突的棋子之间建条边,建好后发现选择的是最大独立集。
图中不可能有奇环,是二分图。
二分图的 最大独立集 = 顶点总数 - 最小路径覆盖 = 顶点总数 - 最大匹配
然后就amzing了呀,具体看代码就行,网络流还是匈牙利随意(网络流更快)
#include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn = 220; const int N = 200000; int list[maxn][maxn]; int id[maxn][maxn]; int n, m; int dis[4][2] = { {-1,-2},{-2,-1},{-2,1},{-1,2} }; vector<int>G[N]; void add(int x, int y) { G[x].push_back(y); } int vis[N]; int match[N]; int dfs(int x) { for (int i = 0; i < G[x].size(); i++) { int p = G[x][i]; if (!vis[p]) { vis[p] = 1; if (!match[p] || dfs(match[p])) { match[p] = x; match[x] = p; return 1; } } } return 0; } int main() { int t; scanf("%d %d %d", &n, &m ,&t); int x, y; for (int i = 0; i < t; i++) { scanf("%d%d", &x, &y); list[x][y] = 1; } int cnt = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { id[i][j] = ++cnt; } } //cout << endl; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (list[i][j]) continue; for (int k = 0; k < 4; k++) { int x = i + dis[k][0]; int y = j + dis[k][1]; if (x >= 1 && x <= n && y >= 1 && y <= m) { if (list[x][y]) continue; add(id[i][j], id[x][y]); add(id[x][y], id[i][j]); } } } } int ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m ; j++) { if (list[i][j]) continue; if (!match[id[i][j]]) { memset(vis, 0, sizeof(vis)); if (dfs(id[i][j])) ans++; } } } ans = cnt - t - ans; printf("%d ", ans); return 0; }