匈牙利算法解决人员分配问题代码

设某单位有n名工作人员x1,x2……xn 和n项工作都y1,y2……yn ,已知每个人至少都能胜任一份工作,每份工作至少有一个人可以胜任。问能否给出一个安排,使每个人都完成一项工作的前提下,完成所有的工作。

** 下面介绍一种求解人员分配问题的算法一一匈牙利方法当G中有完美匹配时,该算法至少求出一个解,否则,图中就没有完美匹配.
从G中任取一个匹配M(称为初始匹配,它可以是一条边),然后实施下列步骤:
(1)若M饱和X的每个顶点,则算法停止(M就是问题的一个解),否则,设u∈X是非M饱和点令S={u},T=空集,转(2);
(2)若NG(S)=T,则|NG(S)|< |S|,算法停止(无解),否则,任取y∈N。NG(S)-T,转(3)
(3)若y是M-饱和的,则令SU{z} ,T=TU{y} ,其中xy属于M,转(2);否则,可得到一台以u为起点,y为终点的M-可增广路P,令M=M^E§,转(1). **

代码奉上

//算法要求,找二分图的饱和其中一个划分的最大匹配,如果二划分点的个数相等,即求完美匹配
#include
#include
int V1,V2,E,cnt;
//两个边集的顶点个数,二划分边的条数,cnt用来记录V1集合中已经匹配的顶点个数
int x[1005],y[1005],link[1005][1005];
//x表示第一个V1划分,x[i]=j表示当前x中的i与y中的j匹配,link[i][j]表示x[i]与y[j]邻接
int T[1005],flag;    //flag用来判断是否可以得出这样的匹配
void input(){
    cnt=0;
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    memset(link,0,sizeof(link));
    printf("请输入你选择饱和的划分中顶点个数:\n");
    scanf("%d",&V1);
    printf("请输入另一个划分中的顶点个数:\n");
    scanf("%d",&V2);
    printf("请输入边的条数\n");
    scanf("%d",&E);
    printf("请依次输入二划分中所有邻接的点:\n");
    for(int i=0;i<E;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        link[a][b]=1;
    }
}
void dfs(int k){//算法中的第二步,判断并找到与x[k]邻接的y点
    if(flag||cnt==V1)    return;
    int i;
    for(i=1;i<=V2;i++){
        if(!T[i]&&link[k][i]){
            if(!y[i])   //找到y中的非饱和点,直接放进匹配
            {
                T[i]=1;
                cnt++;x[k]=i;y[i]=k;
                for(int j=1;j<=V1;j++)
                if(!x[i])   dfs(j);
                break;
            }
            else        //找到饱和点,则更换点,令原来与y[i]匹配的点变成非饱和点
            {
                T[i]=1;
                int tem=y[i];
                y[i]=k;x[k]=i;x[tem]=0;
                dfs(tem);
                break;
            }
        }
    }
    if(i>V2)    flag=1;
}
void Edmonds(){//算法第一步,找到X集合的一个非饱和点
    for(int i=1;i<=V1;i++)//找一个初始匹配M
        for(int j=1;j<=V2;j++)
            if(link[i][j]&&!x[i]&&!y[j]){//如果找到两个点邻接,记录进匹配M
                x[i]=j;
                y[j]=i;
                cnt++;
                break;
            }
    for(int i=1;i<=V1;i++){
        if(flag||cnt==V1)    break;
        memset(T,0,sizeof(T));
        if(!x[i])   dfs(i);
    }
}
void output(){
    if(cnt!=V1){
        printf("找不到匹配.\n");
        return;
    }
    else{
        if(V1==V2)
        printf("已经找到该图的一个完美匹配:\n");
        else if(V1<V2)
        printf("已经找到可以饱和目标集合的一个匹配:\n");
    }
    for(int i=1;i<=V1;i++)
        printf("%d---%d\n",i,x[i]);
}
int main(){
    input();
    Edmonds();
    output();
    return 0;
}

样例:

匈牙利算法解决人员分配问题代码_第1张图片

5
5
13
1 2
1 3
2 1
2 2
2 4
2 5
3 2
3 3
3 4
4 2
4 3
5 4
5 5

你可能感兴趣的:(图论)