UVA 11419 SAM I AM

题意:

给出一个r*c的矩阵,有些格子中有敌人,拥有一个炮塔可以一次消灭一整行或一整列的敌人,求最少的发射次数并输出方案

思路:

极为经典的建模
构造r个点表示r行,c个点表示c列
对于每个敌人,都连接一条对应的边
至于如何输出方案,从x集中出发按照 未选边-已选边-未选边…… 进行覆盖,
最后x的所有未标记点和y的已标记点就是答案(原因参见最小点覆盖=最大匹配的证明)

code:

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int r,c,n,match[N],id[N],rr[N],cc[N],fm[N];
bool lk[N][N];
inline int read()
{
	int s=0,w=1; char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
	return s*w;
}
bool dfs(int x,int lb)
{
	for(int i=1;i<=c;++i)
	{
		if(id[i]==lb||lk[x][i]==0) continue;
		id[i]=lb;
		if(match[i]==-1||dfs(match[i],lb))
		{
			match[i]=x;
			return true;
		}
	}
	return false;
}
void _dfs(int x)
{
	rr[x]=1;
	for(int i=1;i<=c;++i)
	{
		if(lk[x][i]==0||cc[i])continue;
		cc[i]=1;
		_dfs(match[i]);
	}
}
int main()
{
	while(1)
	{
		r=read(),c=read(),n=read();
		if(!r || !c || !n) break;
		for(int i=1;i<=r;++i)
			for(int j=1;j<=c;++j)
				lk[i][j]=0;
		for(int i=1;i<=r;++i)rr[i]=0,fm[i]=-1;
		for(int i=1;i<=c;++i)cc[i]=0;
		for(int i=1;i<=c;++i)id[i]=0,match[i]=-1;
		for(int i=1;i<=n;++i)
		{
			int u=read(),v=read();
			lk[u][v]=1;
		}
		int ans=0;
		for(int i=1;i<=r;++i)
			if(dfs(i,i))++ans;
		printf("%d ",ans);
		for(int i=1;i<=c;++i)fm[match[i]]=i; 
		for(int i=1;i<=r;++i)
			if(fm[i]==-1)_dfs(i);
		for(int i=1;i<=r;++i)
			if(!rr[i])printf("r%d ",i);
		for(int i=1;i<=c;++i)
			if(cc[i]) printf("c%d ",i);
		puts("");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/zmyzmy/p/12599158.html