zoukankan      html  css  js  c++  java
  • LOJ 6033. 「雅礼集训 2017 Day2」棋盘游戏 (二分图匹配问题)

    题面

    LOJ传送门

    题解

    感觉没什么方法可以做。

    但是有巧妙的解法(套路)。

    我们对于所有空地,相邻两个空地连边,显然是二分图。

    然后求出一个最大匹配。如果Alice把一个未匹配点作为起点,那么Bob每一步只能走到一个新的匹配了的位置,那么Alice只要走向这个位置对应匹配的位置就可以了。而Bob如果走向了一个未匹配点,就相当于找到了一条增广路,说明这不是一个最大匹配,矛盾。

    那么只需要求出那些非关键点就行了。这里的关键点的意思是在所有可能的最大匹配中都为匹配点的点。

    方法是用网络流从s和t做两次dfs。

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 10005;
    const int MAXM = 20005;
    const int inf = 1e9;
    char SS[105][105];
    int n, m;
    inline int id(int i, int j) {
    	return (i-1)*m + j;
    }
    int info[MAXN], fir[MAXN], to[MAXM<<1], nxt[MAXM<<1], c[MAXM<<1], cnt = 1;
    inline void link(int u, int v, int cc, int rc=0) {
    	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; c[cnt] = cc;
    	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt; c[cnt] = rc;
    }
    int S, T, dis[MAXN];
    queue<int>q; bool vis[MAXN];
    bool bfs() {
    	memset(dis, -1, sizeof dis);
    	dis[S] = 0; q.push(S);
    	while(!q.empty()) {
    		int u = q.front(); q.pop();
    		for(int i = fir[u]; i; i = nxt[i])
    			if(c[i] && !~dis[to[i]])
    				dis[to[i]] = dis[u] + 1, q.push(to[i]);
    	}
    	return ~dis[T];
    }
    int aug(int u, int Max) {
    	if(u == T) return Max;
    	vis[u] = 1; int flow = 0, delta;
    	for(int v, &i = info[u]; i; i = nxt[i])
    		if(c[i] && !vis[v=to[i]] && dis[v] == dis[u] + 1 && (delta=aug(v, min(Max-flow, c[i])))) {
    			c[i] -= delta, c[i^1] += delta, flow += delta;
    			if(flow == Max) break;
    		}
    	vis[u] = 0; return flow;
    }
    int Maxflow(int s, int t) {
    	int re = 0; S = s, T = t;
    	while(bfs()) memcpy(info, fir, sizeof info), re += aug(S, inf);
    	return re;
    }
    bool viss[MAXN], vist[MAXN];
    void dfsS(int u) {
    	if(viss[u]) return; viss[u] = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(c[i]) dfsS(to[i]);
    }
    void dfsT(int u) {
    	if(vist[u]) return; vist[u] = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(c[i^1]) dfsT(to[i]);
    }
    int main () {
    	scanf("%d%d", &n, &m);
    	int s = n*m+1, t = n*m+2;
    	for(int i = 1; i <= n; ++i) {
    		scanf("%s", SS[i]+1);
    		for(int j = 1; j <= m; ++j)
    			if(SS[i][j] == '.') {
    				if((i+j)&1) link(s, id(i, j), 1);
    				else link(id(i, j), t, 1);
    				if(i > 1 && SS[i-1][j] == '.') {
    					if((i+j)&1) link(id(i, j), id(i-1, j), 1);
    					else link(id(i-1, j), id(i, j), 1);
    				}
    				if(j > 1 && SS[i][j-1] == '.') {
    					if((i+j)&1) link(id(i, j), id(i, j-1), 1);
    					else link(id(i, j-1), id(i, j), 1);
    				}
    			}
    	}
    	Maxflow(s, t);
    	dfsS(s);
    	dfsT(t);
    	int ans = 0;
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if((((i+j)&1) && viss[id(i,j)]) || ((!((i+j)&1) && vist[id(i,j)]))) ++ans;
    	printf("%d
    ", ans);
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if((((i+j)&1) && viss[id(i,j)]) || ((!((i+j)&1) && vist[id(i,j)]))) printf("%d %d
    ", i, j);
    }
    
  • 相关阅读:
    一步一步写数据结构(线索二叉树)
    Android studio 下JNI编程实例并生成so库
    IOS和Android音频开发总结
    IDEA常用快捷键
    Spring事务简介
    IDEA新建Springboot项目
    140201126杨鹏飞作业六
    140201126杨鹏飞作业三
    140201126杨鹏飞作业七
    自我介绍
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12106703.html
Copyright © 2011-2022 走看看