HDU1150 匈牙利算法(求二分图最大匹配)

HDU1150

题目大意;有两台机器A和B以及N个需要运行的任务。每台机器有M种不同的模式,而每个任务都恰好在一台机器上运行。如果它在机器A上运行,则机器A需要设置为模式ai,如果它在机器B上运行,则机器A需要设置为模式bi。每台机器上的任务可以按照任意顺序执行,但是每台机器每转换一次模式需要重启一次。请合理为每个任务安排一台机器并合理安排顺序,使得机器重启次数尽量少。
谈匈牙利算法自然避不开Hall定理
Hall定理:对于二分图G,存在一个匹配M,使得X的所有顶点关于M饱和的充要条件是:对于X的任意一个子集A,和A邻接的点集为T(A),恒有: |T(A)| >= |A|
匈牙利算法是基于Hall定理中充分性证明的思想,其基本步骤为:
1.任给初始匹配M;
2.若X已饱和则结束,否则进行第3步;
3.在X中找到一个非饱和顶点x0,
作V1 ← {x0}, V2 ← Φ;
4.若T(V1) = V2则因为无法匹配而停止,否则任选一点y ∈T(V1)\V2;
5.若y已饱和则转6,否则做一条从x0 →y的可增广道路P,M←M⊕E(P),转2;
6.由于y已饱和,所以M中有一条边(y,z),作 V1 ← V1 ∪{z}, V2 ← V2 ∪ {y}, 转4;

二分图的最小顶点覆盖数=最大匹配数
本题就是求最小顶点覆盖数的。

每个任务建立一条边。
最小点覆盖就是求最少的点可以连接到所有的边。本题就是最小点覆盖=最大二分匹配数。

注意一点就是:题目说初始状态为0,所以如果一个任务有一点为0的边不要添加。因为不需要代价
AC代码:

#include<stdio.h>
#include<vector>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
vector < vector <int > >v;
bool used[101],used1[101];
int beg[101];
int n,m,k,a,e,r;
bool bfs(int to)
{
    int s=beg[to];
    for(int i=0; i<v[s].size(); i++)
    {
        int point=v[s][i];
        if(used1[point]) continue;
        used1[point]=true;
        if(beg[point]==-1||bfs(point))
        {
          beg[point]=s;
          return true;
        }
    }
    return false;
}
int slove()
{
    int num=0;
    bool foo=false;
    memset(used,false,sizeof(used));
    memset(beg,-1,sizeof(beg));
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<v[i].size(); j++)
        {
            if(beg[v[i][j]]==-1)
            {
                beg[v[i][j]]=i;
                used[i]=true;
                num++;
                if(i==0)
                    foo=true;
                break;
            }
        }
    }
    for(int i=0; i<n; i++)
    {
        if(!used[i])
        {
            if(!v[i].empty())
            {
                memset(used1,false,sizeof(used1));
                for(int j=0; j<v[i].size(); j++)
                {
                    int point=v[i][j];
                    if(used1[point]) continue;
                    used1[point]=true;
                    if(beg[point]==-1||bfs(point))
                    {
                        beg[point]=i;
                        num++;
                        break;
                    }

                }
            }
            used[i]=true;
        }
    }
  if(beg[0]!=-1)
    num--;
    if(foo)
        return num-1;
    else return num;
}
int main()
{
    while(scanf("%d",&n)&&n)
    {
       v.clear();
       v.resize(n);
        scanf("%d%d",&m,&k);
        for(int i=0; i<k; i++)
        {
            scanf("%d%d%d",&a,&e,&r);
            v[e].push_back(r);
        }
        printf("%d\n",slove());
    }
}

你可能感兴趣的:(匈牙利算法)