1 2 3 4

二分图的最大独立集

传送门 : 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\n", ans);
	return 0;
}

  

posted @ 2020-07-10 17:06  Lesning  阅读(299)  评论(0编辑  收藏  举报