二分图题目

矩阵游戏

对于每一个黑块,我们将它横纵坐标连边。如果每个点都可以匹配上那么就有解。

Sorting Slides

将可以对应上的幻灯片和编号连上,我们枚举每一条边,将它删除。如果删除后最大匹配数不变,那么这条边不是匹配所必需的。否则说明每一种匹配都需要这条匹配边,即为答案之一。

[JSOI2009]游戏

考虑黑白染色,求出一组最大匹配。考虑先手选择非匹配点,后手一定只能再走到匹配点,否则的话与最大匹配矛盾。

后手走到匹配点后先手沿着匹配边走,最后一定是后手无路可走。路径一定是 非匹配边 -> 匹配边 -> 非匹配边 -> ... -> 匹配边。假设最后是后手走的非匹配边,那么这必然是一条增广路,又与最大匹配不符。

现在问题转化为一张二分图有多少个点可以删掉并且最大匹配数不变。我们可以分别从 \(s,t\) 轮流走非匹配边,匹配边,走到的同一侧的点就是可以删掉的非必要点。因为所走的路径也可以是一条增广路径(雾)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

int read()
{
	int a = 0,x = 1;char ch = getchar();
	while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
	return a*x;
}
const int N=1e6+7,inf=1e9+7;
int n,m,s,t,x[] = {-1,0,0,1},y[] = {0,-1,1,0},bel[N],vis[N],ab[N],flag,dis[N],cur[N];
char S[109];

int head[N],go[N],nxt[N],cnt(1),lim[N],arr[107][107],id[107][107];
void add(int u,int v,int w)
{
	go[++cnt] = v;
	nxt[cnt] = head[u];
	head[u] = cnt;
	lim[cnt] = w;
}

bool BFS()
{
	for(int i = s;i <= t;i ++) dis[i] = 0;
	queue<int>q;q.push(s);dis[s] = 1;
	while(!q.empty()) {
		int u = q.front();q.pop();
		for(int e = head[u];e;e = nxt[e]) {
			int v = go[e];if(dis[v] || !lim[e]) continue;
			dis[v] = dis[u] + 1;q.push(v);
		}
	}
	return dis[t];
}

int DFS(int u,int limit)
{
	if(u == t || !limit) return limit;
	int ret = 0;
	for(int &e = head[u];e;e = nxt[e]) {
		int v = go[e];
		if(dis[v] != dis[u] + 1 || !lim[e]) continue;
		int tmp = DFS(v,min(limit,lim[e]));
		limit -= tmp,ret += tmp;
		lim[e] -= tmp,lim[e^1] += tmp;
		if(!limit) break;
	}
	return ret;
}

void dfs(int u,int w)
{
	if(vis[u]) return ;
	vis[u] = 1;
	if(bel[u] == w) ab[u] = 1,flag = 1;
	for(int e = head[u];e;e = nxt[e]) {
		int v = go[e];if(lim[e] == w) dfs(v,w);
	}
}

int main()
{
	// freopen("random.in","r",stdin);
	// freopen("sol.out","w",stdout);
	n = read(),m = read(),s = 0,t = n*m+1;
	for(int i = 1;i <= n;i ++) {
		scanf("%s",S+1);
		for(int j = 1;j <= m;j ++) {
			arr[i][j] = (S[j] == '.');
			id[i][j] = (i-1)*n+j;
		}
	}
	for(int i = 1;i <= n;i ++) {
		for(int j = 1;j <= m;j ++) {
			if(arr[i][j] && ((i+j)&1)) {
				bel[id[i][j]] = 1;
				add(s,id[i][j],1);add(id[i][j],s,0);
				for(int k = 0;k < 4;k ++) {
					int p = i+x[k],q = j+y[k];
					if(arr[p][q] && p >= 1 && p <= m && q >= 1 && q <= m) add(id[i][j],id[p][q],1),add(id[p][q],id[i][j],0);
				}
			} else if(arr[i][j] && !((i+j)&1)) add(id[i][j],t,1),add(t,id[i][j],0);
		}
	}
	int ans = 0;
	for(int i = s;i <= t;i ++) cur[i] = head[i];
	while(BFS()) {
		ans += DFS(s,inf);
		for(int i = s;i <= t;i ++) head[i] = cur[i];
	}
	dfs(s,1);memset(vis,0,sizeof(vis));dfs(t,0);
	if(!flag) puts("LOSE");
	else {
		puts("WIN");
		for(int i = 1;i <= n;i ++) {
			for(int j = 1;j <= m;j ++) {
				if(ab[id[i][j]]) printf("%d %d\n",i,j);
			}
		}
	}
	return 0;
}
posted @ 2021-04-19 13:48  nao-nao  阅读(31)  评论(0编辑  收藏  举报