POJ1325 Machine Schedule【二分图最小点覆盖】

题目链接:

http://poj.org/problem?id=1325


题目大意:

有两台机器A和B,机器A有N种不同的模式,编号为0~N-1。机器B有M种不同的模式,编号为0~M-1。

在一开始的时候,机器A和B都处于0模式。现在需要用两台机器来处理K项任务,任务编号为0~K-1。每

一项任务都可以在A或B的指定状态下完成。例如任务1可以在机器A的2模式下完成,也可以在机器B的4

模式下完成。对于第i想任务用(i,x,y)来表示第i项任务可以在机器A的x模式下或机器B的y模式下完成。

为了完成所有任务,不得一次次地切换机器的工作模式。而切换机器的工作模式只能通过重启机器来完

成。那么问题来了:最少需要重启多少次机器,能够完成这K项任务。


思路:

建立一个二分图,一边为机器A,另一边为机器B。一项任务既能在机器A的x模式或是机器B的y模式下完

成,则在二分图中建立一条边(x,y)。求最少的机器切换次数,就是求是否存在一个最小规模的点集,使

得所有的边都至少和这个点集中的一个点相关联,也就是求二分图最小点集覆盖。而二分图最小点覆盖等

于二分图最大匹配,直接用匈牙利算法就可以求出了。


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 110;

bool Map[MAXN][MAXN],Mask[MAXN];

int NX,NY;
int cx[MAXN],cy[MAXN];

int FindPath(int u)
{
    for(int i = 0; i < NY; ++i)
    {
        if(Map[u][i] && !Mask[i])
        {
            Mask[i] = 1;
            if(cy[i] == -1 || FindPath(cy[i]))
            {
                cy[i] = u;
                cx[u] = i;
                return 1;
            }
        }
    }
    return 0;
}

int MaxMatch()
{
    for(int i = 0; i < NX; ++i)
        cx[i] = -1;
    for(int i = 0; i < NY; ++i)
        cy[i] = -1;

    int res = 0;
    for(int i = 0; i < NX; ++i)
    {
        if(cx[i] == -1)
        {
            for(int j = 0; j < NY; ++j)
                Mask[j] = 0;
            res += FindPath(i);
        }
    }
    return res;
}

int main()
{
    int N,M,K,a,u,v;
    while(~scanf("%d",&N) && N)
    {
        memset(Map,0,sizeof(Map));
        scanf("%d%d",&M,&K);
        NX = N,NY = M;
        for(int i = 1; i <= K; ++i)
        {
            scanf("%d%d%d",&a,&u,&v);
            if(u*v != 0)
                Map[u][v] = 1;
        }
        printf("%d\n",MaxMatch());
    }

    return 0;
}


你可能感兴趣的:(POJ1325 Machine Schedule【二分图最小点覆盖】)