zoukankan      html  css  js  c++  java
  • 最小点覆盖 最大独立集

    最小点覆盖

    在二分图中,找出一个最小的点集,使之覆盖所有的边,这个问题被称为二分图的最小点覆盖。

    König定理:

    二分图最小点覆盖包含的点数等于这个二分图的最大匹配数。
    证明:
    1.求出二分图的最大匹配,定义:匹配边为包含在最大匹配里的边,匹配点为与匹配边相连的点。
    2.从二分图右部的非匹配点开始,按照:非匹配边->匹配边->非匹配边......(交错路)依次将遍历到的结点打上标记。
    3.选取左部标记点和右部未标记点即可构成最小点覆盖。
    证明懒得写了

    二分图最小点覆盖模型特点(“2要素”):每个边有两个端点,两个端点任选其一即可。

    题目:POJ 2226
    题解:
    显而易见:木板越长越好。
    对于一个泥地,要么被横着的木板挡住,要么被竖着的木板挡住。先预处理挡住每个泥地木板编号,将横着的木板作为右部结点,竖着的作为左部端点,连边求出最小点覆盖即为答案。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int N = 2505;
    const int M = 5000;
    int n, m, map[N][N], tot = 0, match[M], tot1 = 0;
    int head[N], nextt[M << 1], to[M << 1], cnt = 0;
    void add(int x, int y) {
    	nextt[++cnt] = head[x];
    	to[cnt] = y; head[x] = cnt;
    }
    struct node {
    	int len, row;
    } e[N][N];
    bool vis[M];
    bool dfs(int x) {
    	for(int i = head[x]; i; i = nextt[i]) {
    		int y = to[i];
    		if(vis[y]) continue;
    		vis[y] = true;
    		if(!match[y] or dfs(match[y])) {
    			match[y] = x; return true;
    		}
    	}
    	return false;
    }
    int main() {
    //	freopen("data.in", "r", stdin);
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) {
    			char s; cin >> s;
    			if(s == '.') map[i][j] = -1;
    		}
    	}
    	tot = 1;
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m;) {
    			if(map[i][j] == -1) {
    				tot++; 
    				while(map[i][j] == -1 && j <= m) j++;
    			} else {
    				while(map[i][j] != -1 && j <= m) {
    					e[i][j].len = tot; j++;
    				}
    				if(j > m) tot++; 
    			}
    		}
    	}
    	tot1 = 1;
    	for(int j = 1; j <= m; j++) {
    		for(int i = 1; i <= n;) {
    			if(map[i][j] == -1) {
    				tot1++; 
    				while(map[i][j] == -1 && i <= n) i++;
    			} else {
    				while(map[i][j] != -1 && i <= n) {
    					e[i][j].row = tot1; i++;
    				}
    				if(i > n) tot1++; 
    			}
    		}
    	}
    	int ans = 0;
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) {
    			if(e[i])
    			add(e[i][j].row, e[i][j].len);
    		}
    	}
    	for(int i = 1; i <= tot1; i++) {
    		memset(vis, 0, sizeof(vis));
    		if(dfs(i)) ans++;
    	}
    	printf("%d", ans);
    	return 0;
    }
    

    最大独立集

    在二分图中,找出最大的点集,使其中任意两个点都没有边直接相连,这个点集就是最大独立集

    最大独立集 = 点数 - 最大匹配

    证明:
    显然。
    选取最多的点构成独立集 <==> 用最少的点覆盖边,总点数去掉最小点覆盖后剩下的点之间没有边直接相连
    证毕。

    题目:P3355 骑士共存问题
    题解:对棋盘进行黑白染色,分成两部分作为左右部结点,能互相攻击到的格子之间连边(观察可知,一种颜色的格子无法攻击和它颜色相同的格子,所以连完边后构成一张二分图)求出最大独立集即为答案。

  • 相关阅读:
    GetHub下载不成功
    Cache 判断Ip几分钟内攻击次数
    .net 通过Url获取站点json数据
    Linq 读取Xml 数据
    ef Linq 自定义字段列表
    面试的心得
    触发器--单独字段变化另一个字段也变化
    Ajax跨域 取值 Jsonp的定义注意事项
    asp.net里,各种下载方式汇总
    c# 获取硬件信息
  • 原文地址:https://www.cnblogs.com/mcggvc/p/12719401.html
Copyright © 2011-2022 走看看