//相关知识点
¥ 最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数 M
¥ 简单的证明如下:
¥ (1)M个是足够的。只需要让它们覆盖最大匹配的M条边,则其它边一定被覆盖(如果有边e不被覆盖,把e加入后得到一个更大的匹配)
¥ (2)M个是必需的,仅考虑形成最大匹配的这M条边,由于它们两两之间没有公共点,因此至少需要M个点才可以把它们覆盖
对于这题 那个数据我们可以用下面的表示,0表示无障碍物,1表示有;
1 0 1
0 1 0
0 1 0
首先,我们利用行跟列做二分图:
如果第i行的第j列有障碍物,则在图中左边的i行连一条边到右边的j列,上面的数据
于是问题就转化成最小点覆盖的问题.求最大匹配即可.
Code:
#include<iostream>
using namespace std;
bool map[502][502];
int linkx[502],linky[502];//linkx表示x所对应的y,linky表示y所对应的x
bool used[502];
int n;
int path(int x)
{
for(inti=1;i<=n;i++)//y轴遍历
{
if(!used[i]&&map[x][i])
{
used[i]=true;//别忘咯
if(linky[i]==-1||path(linky[i]))
{
linky[i]=x;
linkx[x]=i;
return1;
}
}
}
return0;
}
int main()
{
intk,num,a,b,i;
while(scanf("%d%d",&n,&k)!=EOF)
{
memset(map,false,sizeof(map));
while(k--)
{
scanf("%d%d",&a,&b);
map[a][b]=true;
}
num=0;
memset(linkx,0xff,sizeof(linkx));
memset(linky,0xff,sizeof(linky));
for(i=1;i<=n;i++)//x轴
{
if(linkx[i]==-1)//x轴不存在路径
{
memset(used,false,sizeof(used));
num+=path(i);//
}
}
printf("%d\n",num);
}
return0;
}