Interesting Housing Problem----KM

来源:互联网 发布:腾讯云申请域名绿标 编辑:程序博客网 时间:2024/05/17 21:57

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2426

注:

1)   二分图中边权为负值时,不匹配 (he still wants to design a creative plan such that no student is assigned to a room he/she dislikes)

2)   KM算法中如果无法进行匹配成功,就会进入死循环 (所以我选择用最大二分匹配 先进行匹配)

3)   还有就是如果是邻接矩阵储存的话,要考虑到矩阵的初始化


源代码:

/*==============================================================================*\二分图最佳匹配(kuhn munkras算法)最大权匹配/最小权匹配,复杂度O(n^3)\*==============================================================================*/#include <stdio.h>#include <string.h>#include <algorithm>#define N 505              //N是X的顶点数最大值 M是Y的顶点数最大值 #define M 5005#define INF 1e9#define fin -10001        //g[][]的初值,绝对值大于边权的最大值using namespace  std;int u,v,w,e;int g[N][M],nx,ny; //需要初始化    nx是X的顶点数  ny是Y的顶点数int mx[N],my[M],lx[N],ly[M]; //lx[],ly[]为KM算法中Xi与Yi的顶点标号  mx[]是匹配后X中对应的Y的顶点编号  my[]是匹配后Y中对应的X的顶点编号bool sx[N],sy[N]; //标记是否在交错树上int prev[N],slack[N]; //prev[i]为Y中i点在交错树上的前点;slack为松弛量int q[2*N],head,tail;bool chk[N];   //标记数组bool search(int u){    for(int v=0;v<ny;v++)     if(g[u][v]>-1&&!chk[v])    {        chk[v]=true;        if(my[v]==-1||search(my[v]))        {            my[v]=u;  mx[u]=v;            return true;        }    }    return false;}int Maxmatch(){    int ret=0;    memset(mx,-1,sizeof(mx));    memset(my,-1,sizeof(my));    for(int u=0;u<nx;u++)    if(mx[u]==-1)    {        memset(chk,false,sizeof(chk));        if(search(u))  ret++;    }    return ret;}void augment(int v){ //增广    while(v!=-1){        int pv=mx[prev[v]];        mx[prev[v]]=v; my[v]=prev[v];v=pv;    }}bool bfs(){    while(head!=tail){        int p=q[head++],u=p>>1;        if(p & 1){            if(my[u]==-1){ augment(u);return true;            }            else {  q[tail++]=my[u]<<1; sx[my[u]]=true;            }        }        else            for(int i=0;i<ny;i++)                if(sy[i]) continue;                else if(lx[u]+ly[i]!=g[u][i]){                        int ex=lx[u]+ly[i]-g[u][i];                        if(slack[i]>ex){ slack[i]=ex; prev[i]=u; }                        }                    else { prev[i]=u; sy[i]=true; q[tail++]=i*2+1; }    }    return false;}int KMmatch(bool maxsum ){ //默认为最大权匹配    int i,j,ex,cost=0;    if(!maxsum) for(i=0;i<nx;i++)        for(j=0;j<ny;j++) g[i][j]*=-1;    memset(mx,-1,sizeof(mx));    memset(my,-1,sizeof(my));    memset(ly,0,sizeof(ly));    for(i=0;i<nx;i++)        for(lx[i]=-INF,j=0;j<ny;j++)            lx[i]=max(lx[i],g[i][j]);    for(int live=0;live<nx;live++){        memset(sx,0,sizeof(sx));        memset(sy,0,sizeof(sy));        for(i=0;i<ny;i++)slack[i]=INF;            head=tail=0; q[tail++]=live*2; sx[live]=true;            while(!bfs()){                for(ex=INF,i=0;i<ny;i++)    if(!sy[i]) ex=min(ex,slack[i]);                for(i=0;i<nx;i++)    if(sx[i])lx[i]-=ex;                for(j=0;j<ny;j++){ if(sy[j])ly[j]+=ex;slack[j]-=ex;}                for(i=0;i<ny;i++)                if(!sy[i] && slack[i]==0){q[tail++]=i*2+1;sy[i]=true;}            }    }    if(!maxsum) for(i=0;i<nx;i++) for(j=0;j<ny;j++) g[i][j]*=-1;    for(i=0;i<nx;i++)cost+=g[i][mx[i]];    return cost;}int main(){     int k=0;   //freopen("D:\\a.txt","r",stdin);    while(~scanf("%d %d %d",&nx,&ny,&e))    {        k++;        memset(g,fin,sizeof(g));        for(int i=0;i<e;i++)        {            scanf("%d %d %d",&u,&v,&w);            if(w>=0) g[u][v]=w;        }        if(Maxmatch()!=nx)            printf("Case %d: -1\n",k);        else       printf("Case %d: %d\n",k,KMmatch(true));    }}

几组测试数据:

2 2 4
0 0 1
0 1 4
1 0 -1
1 1 1 

2 1 2
0 0 2
1 0 3

3 3 3
0 0 8
1 0 9
2 2 10

原创粉丝点击