zoukankan      html  css  js  c++  java
  • 二分图题目

    矩阵游戏

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

    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
    ",i,j);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java虚拟机详解(二)------运行时内存结构
    Java虚拟机详解(一)------简介
    分布式任务调度平台XXL-JOB搭建教程
    Kafka 详解(三)------Producer生产者
    服务器监控异常重启服务并发送邮件
    超详细的Linux查找大文件和查找大目录技巧
    linux清理磁盘空间
    Magent实现Memcached集群
    Nginx反爬虫: 禁止某些User Agent抓取网站
    redis集群搭建详细过程
  • 原文地址:https://www.cnblogs.com/nao-nao/p/14676474.html
Copyright © 2011-2022 走看看