UVA1194 Machine Schedule[二分图最小点覆盖]

题意翻译

有两台机器 A,B 分别有 n,m 种模式。

现在有 k 个任务。对于每个任务 i ,给定两个整数$ a_i\(和\) b_i$,表示如果该任务在 A上执行,需要设置模式为 \(a_i\);如果该任务在 B** 上执行,需要设置模式为$ b_i$。

每台机器第一次开机默认处在0模式,且第一次开机不需要消耗时间。任务可以以任意顺序被执行,但每台机器转换一次模式就要重启一次。求怎样分配任务并合理安排顺序,能使机器重启次数最少。

1 \leq n,m \leq 1001≤n,m≤100,1 \leq k \leq 10001≤k≤1000,1 \leq a_i \leq n1≤ain,1 \leq b_i \leq m1≤bim

可能有多组数据。

解析

二分图最小点覆盖。

容易看出,这就是一张二分图,A、B的不同模式分别是左部和右部的点。

我们要解决的问题是,对于任意一个任务,我们可以把它看作一条边。对于这条边,我们必须要选择二分图中任意一部的点,即最小点覆盖。

定理

二分图最小点覆盖包含点数=二分图最大匹配数

根据这个定理,我们用匈牙利求最大匹配就行。

参考代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#define N 1010
using namespace std;
int n,m,k,f[N];
vector<int> g[N];
bitset<N> v;
inline bool dfs(int x)
{
    for(int i=0;i<g[x].size();++i){
        int y=g[x][i];
        if(v[y]) continue;
        v[y]=1;
        if(!f[y]||dfs(f[y])){
            f[y]=x;
            return 1;
        }
    }
    return 0;
}
int main()
{
    while(~scanf("%d",&n)&&n!=0){
        for(int i=1;i<=n;++i) g[i].clear();
        v.reset();memset(f,0,sizeof(f));
        scanf("%d%d",&m,&k);
        while(k--){     
            int num,u,v;
            scanf("%d%d%d",&num,&u,&v);
            g[u].push_back(v+n),g[v+n].push_back(u);
        }
        getchar();
        int ans=0;
        for(int i=1;i<=n;++i){
            v.reset();ans+=dfs(i);
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DarkValkyrie/p/11371924.html