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

来源:互联网 发布:网络和共享中心打不开 编辑:程序博客网 时间:2024/05/27 14:12

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());    }}
0 0
原创粉丝点击