//相關知識點
¥ 最小覆蓋: 最小覆蓋要求用最少的點(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;
}