二分图的最大匹配之最小点集覆盖

本文通过一个POJ题目3041,介绍如何应用二分图理论解决最小点集覆盖问题。在N*N的平面上,如何用最少的子弹摧毁所有小行星。构建二分图后,问题转化为求解最大匹配,从而找到最小点集覆盖。通过求解二分图的最大匹配,可以得到最少所需的子弹数量。
摘要由CSDN通过智能技术生成

http://poj.org/problem?id=3041

题意:

在N*N(1 <= N <= 500)的平面上有K颗小行星,现在你要摧毁他们,你的每一发子弹可以摧毁同一行,或者是同一列上的小行星,现在问你最少要多少子弹才能摧毁所有的小行星?

分析:

构造一个二分图,用每行的行号做集合1中的点,用每行的列号做集合2中的点,如果第 i 行第 j 列有一个小行星,就可以把集合1中的 i 行点与集合2中的 j 号点连一条边。

构造好二分图之后,会发现,现在的问题变成了找出最小的一个点集,使所有的边至少有一个点在该点集内。

这就是典型的最小点集覆盖问题了,而于由二分图最小覆盖点集等于其最大匹配(一个经典的定理,证明在http://www.matrix67.com/blog/archives/116,其中还有怎样求具体的最小覆盖集中的点的方法 ),可知,只用求该二分图的最大匹配就行了。


代码:

#pragma warning (disable:4786)  
#include<iostream>
using namespace std;

int match[505];
int map[505][505];
int visited[505];
int n;

//寻找起点为点集1中的node的增广轨
bool find( int node ){
	int i;

	/// 对点集2中的每个与node有边相连的点 i , 如果 i 还没有与之匹配的点,则将node 与 i 配对,
	/// 如果 i 已与点 j 配对,则搜索有无其他的可与 j 配对的点 k,如果 k 存在,则将 j 与 k 配
	/// 对,node与 i 配对,这就使原本的配对集 { i—j } 拓展到了 { node—i ,j—k },增加了一条匹配边
	for( i = 1; i <= n; i ++ ){
		if( !visited[i] && map[node][i] == 1 ){
			visited[i] = 1;
			if( match[i] == 0 || find( match[i] ) ){
				match[i] = node;
				return true;
			}
		}
	}
	return false;
}
		
int main(){
	int i,k,sum = 0;
	scanf("%d%d",&n,&k);
	int x,y;
	memset( match, 0, sizeof( match ) );
	memset( map, 0, sizeof( map ) );

	for( i = 0; i < k; i ++ ){
		scanf("%d%d",&x,&y);;
        map[x][y] = 1;
	}

    // 对点集1中的每个点寻找增广轨
	for( i = 1; i <= n; i ++ ){
		memset( visited, 0, sizeof( visited ) );
		if( find(i) )
			sum ++;
	}
	printf("%d\n", sum);
		
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值