HDU 1150 Machine Schedule 最小点覆盖

转载请注明本文地址


学习了二分图的邻接矩阵存储方式,原来二维刚好表示二分图……不是按照所有的点的存法


题意:有两个机器A和B,分别有mode_0,mode_1...mode_n-1和mode_0,mode_1...mode_m-1,初始均在mode_0。现在有k个job,每个job可以在A的mode_x或者B的mode_y下完成。每次重新选择模式要重启机器。问最少重启多少次机器能完成所有工作。


思路:

1.首先要注意一开始就是在mode_0,所以输入中如果有可以在mode_0下完成的就不用理睬了。

2.把A的n种模式看成n个点,属于一个集合,B的m种模式看成m个点,属于另一个集合。然后一个(x,y)就表示两个集合之间有连接A的mode_x与B的mode_y的边。然后就是要求最小点覆盖。

注:最小顶点覆盖是这个意思:对每条边,其两个顶点中的任一个是“存在”的,那视作这条边“被覆盖”,现在用最少的顶点数,使所有边都被覆盖(也就是使所有边的至少一个端点“存在”)。

3.无向图中求最小顶点覆盖问题是NP-hard问题,但是二分图中其等于最大匹配数(证明见这里),所以直接求一遍最大匹配就可以了。

4.注意邻接矩阵的二维刚好存二分图的二维……而不是存所有的顶点。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>

using namespace std;

const int MAXV=110;

bool map[MAXV][MAXV],vis[MAXV];
int match[MAXV];
int n,m,k;

void init()
{
    memset(map,false,sizeof(map));
    memset(match,-1,sizeof(match));
}

bool DFS(int u)
{
    for(int v=0;v<n;v++)
    {
        if(map[u][v] && !vis[v])
        {
            vis[v]=true;
            if(match[v]==-1 || DFS(match[v]))
            {
                match[v]=u;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int ans=0;
    for(int u=0;u<n;u++)
    {
        memset(vis,false,sizeof(vis));
        if(DFS(u)) ans++;
    }
    return ans;
}

int main()
{
    while(scanf("%d",&n),n)
    {
        scanf("%d%d",&m,&k);
        init();
        int index,x,y;
        for(int i=0;i<k;i++)
        {
            scanf("%d%d%d",&index,&x,&y);
            if(x && y)
            {
                x--,y--;
                map[x][y]=true;
            }
        }
        printf("%d\n",hungary());
    }
    return 0;
}


你可能感兴趣的:(HDU 1150 Machine Schedule 最小点覆盖)