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;
}
posted @ 2021-07-14 01:50  acmloser  阅读(23)  评论(0编辑  收藏  举报