POJ - 3041 Asteroids 二分图匹配,个人理解和做法

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

题意: n×n的网络中有k个怪兽(i,j),你的一次攻击可以消灭一整行或者一整列的怪兽,问你最少需要进行多少次攻击才能把怪兽消灭完毕。(改了一下题面描述2333)

 

一开始我又双想到的是贪心,策略就是一次尽可能消灭多的怪兽,结果在我意料当中,这种贪心显然行不通。(每次我觉得可以贪心就不能用贪心做orz。。)

1 1 0 0

1 0 1 0

1 0 0 1  (1表示怪兽0表示没有,你给我贪啊!贪!。。。。)

其实我一直都没意识到是二分图,可能是我二分图除了模板题就没做过其他题的原因(其实是菜。。)

这道题假如以怪兽建图的话比较难建,题解是以攻击建图。

因为目的是消灭完所有的怪兽,所以每只怪兽都必定会受到攻击,攻击的来源只有两种,横向攻击和纵向攻击,因此我们可以以攻击的横纵建立二分图。图的一边以: 第一行横线攻击,第二行横向攻击…… 来建立顶点,另外一边则用纵向攻击为顶点。以怪兽会受到的攻击为边,比如 (1,2)的怪兽可以被 第一行行攻击以及第二列列攻击杀死,因此就有一条边链接(1,2)。那么如此要消灭完所有怪兽,就是所有的边都至少链接一个顶点。

对于同一个顶点而言,连接它的边无论有多少条,我们都只需要选择其中一条边就可以代表它了,因此我们只需要找出这幅图的最大二分匹配就可以了。

对于二分匹配推荐一个博客: https://blog.youkuaiyun.com/dark_scope/article/details/8880547

代码:(使用匈牙利算法)

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn=10005;
int n,m;
vector<int> V[maxn]; 
int used[maxn],match[maxn];
bool bfs(int num){
	used[num]=1;
	for(int i=0;i<V[num].size();i++){
		int to=V[num][i];
		if((!match[to])||(!used[match[to]]&&bfs(match[to]))){ 
			match[to]=num;
			return 1;
		}
	}
	return 0;
}
int two_part_matching(){ //二分匹配模板哟 
	memset(match,0,sizeof(match));
	memset(used,0,sizeof(used));
	int res=0;
	for(int i=1;i<=n;i++){
		memset(used,0,sizeof(used)); 
		if(bfs(i)){
			res++;
		}
	}
	return res;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int num1,num2;
		scanf("%d %d",&num1,&num2);
		V[num1].push_back(num2);
	}
	cout<<two_part_matching()<<endl;
	return 0;
} 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值