题目意思是一次可以毁掉一行或者一列,要求至少毁多少次才能将图上的x都消灭掉。
简单的解释一下最小点覆盖:在图中用最少的点,覆盖图中所有的边
将每一行或者列想象成点,每个x想象成一条边,于是此题很自然的转换成为了最小点覆盖问题。
而二分图的最小点覆盖数 = 二分图的最大匹配。
于是就用匈牙利算法求这个图的最大匹配就好啦。
用人和座位分别表示二分图的x集和y集,于是匈牙利算法大概每一趟过程可以描述成以下形式
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int used[10004];//注释1
vector<int> map[504];//用二维向量模拟邻接表
int per[10004];// per[x]的意思是x号座位上坐的是谁
int n, m;
bool find(int x);
int main()
{
int ans = 0;
scanf("%d%d",&n,&m);
int h,l;
for(int i=0; i<m; i++)
{
scanf("%d%d",&h,&l);
map[h].push_back(l);
}
for(int i=1; i<=n; i++)
{
memset(used,0,sizeof(used));
if(find(i) )
ans++;
}
printf("%d",ans);
return 0;
}
bool find(int x){
for(int i=0; i<map[x].size(); i++)//遍历x号老哥能坐的所有座位
{
if( !used[map[x][i]] ) //注释1
{
used[map[x][i]] = 1;
if( per[map[x][i]] == 0 || find(per[map[x][i]]))
{
per[map[x][i]] = x;
return true;
}
}
}
return false;
}
注释1的解释:
四号大哥只能坐3号位置,为了防止一个一个腾座位的时候,有人将3号座位又坐了,因此加以标记。表示几号座位是准备给腾出来的,不能在腾的过程中让别人坐了