AcWing 376. 机器任务
原题链接
考察:二分图匹配
思路:
对于每个\(a[i],b[i]\)连接边,需要选择最少的点,覆盖所有的边.
对于二分图匹配问题,每个点只能枚举一次.
最小点覆盖问题,两个端点连接的边只能选择其中一个,然后覆盖所有的边.
Code
#include <iostream>
#include <cstring>
#include <set>
using namespace std;
typedef pair<int,int> PII;
const int N = 110,K = 1010;
int h[N<<1],idx,k,A[K],g[2][N],match[N<<1],n,m;
bool st[N<<1];
set<int> s;
struct Road{
int to,ne;
}road[K<<1];
void add(int a,int b)
{
road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
bool dfs(int u)
{
for(int i=h[u];~i;i=road[i].ne)
{
int v = road[i].to;
if(st[v]) continue;
st[v] = 1;
if(match[v]==-1||dfs(match[v]))
{
match[v] = u;
return 1;
}
}
return 0;
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&k)!=EOF&&n)
{
idx = 0;
memset(h,-1,sizeof h);
memset(match,-1,sizeof match);
memset(g,0,sizeof g);
int tot = 0;
s.clear();
for(int j=1;j<=k;j++)
{
int i,a,b; scanf("%d%d%d",&i,&a,&b);
if(!a||!b) continue;
if(!g[0][a]) g[0][a] = ++tot;
if(!g[1][b]) g[1][b] = ++tot;
s.insert(g[0][a]);
add(g[0][a],g[1][b]),add(g[1][b],g[0][a]);
}
int ans = 0;
for(auto i:s)
{
memset(st,0,sizeof st);
if(dfs(i)) ans++;
}
printf("%d\n",ans);
}
return 0;
}