HDU_2853 Assignment KM算法

来源:互联网 发布:什么软件可以构图 编辑:程序博客网 时间:2024/06/05 06:33

http://acm.hdu.edu.cn/showproblem.php?pid=2853

题意:
有N只军队和M项任务,每只军队要被分配一项任务,并且恰好只有一项任务,N<=M

每只军队分配每项任务都有一个效率值,现在已经有了一种分配的策略,求一种最

的分配改变,使得总的效率最大,给出改变的军队数和增加的效率数。

思路:

最大权的最优匹配的一个题目,题目的第二问很好想,只要用KM算法匹配出最大权,

然后减去最初匹配的sum就是最后的答案,关键是第一问,怎么求出最小的改变次数。

首先我们肯定是需要对这些一开始就已经被分配的边做上标记,要不然的话就没有办

法在匹配的时候分清楚两者了,但是我们应该怎么标记呢?一种很巧妙的方法是这样

的,我们先将所有的边乘上一个100 ,然后对那些原来就被分配的边+1,这样最终求

出的最大权匹配也就能保证改变的边最少。下面给出简要的证明:每条原先就被分配

的边都被+1之后,我们最后求出来的权值和是所有完备匹配里最大的,也就是说res

%100之后的值也是最大的,而res%100就是我们留下来的边的数目,这样也就同时保

证了改变的边最小了。思路真的是很巧妙,值得反思。


代码:

#include<stdio.h>#include<string.h>#define CC(m,what) memset(m,what,sizeof(m))#define FF(i , CH) for(int i=0;i<CH;i++)int N ,M ;const int MAXN = 55 ;int w[MAXN][MAXN] ;int lx[MAXN] , ly[MAXN]  ,slack[MAXN] ,match[MAXN];bool sx[MAXN] , sy[MAXN] ;const int inf = (1<<30) ;bool dfs(int u){    sx[u] = 1 ;    FF(v, M){        if( sy[v] )     continue ;        int t = lx[u] + ly[v] - w[u][v] ;        if(t == 0){            sy[v] = 1 ;            if( match[v]==-1 || dfs(match[v])){                match[v] = u ;return true ;            }        }        else if(slack[v] > t)            slack[v] = t;    }    return false ;}int KM(){    CC(match, -1) ; CC(ly, 0) ;    FF(i , M){        lx[i] = -inf ;        FF( j ,M){            if(lx[i] < w[i][j])                lx[i] = w[i][j] ;        }    }    FF(i , M){        FF(j , M) slack[j] = inf ;        while(1){            CC(sx, 0) ; CC(sy, 0 ) ;            if( dfs(i) ) break;            int d = inf ;            FF(j , M){                if( !sy[j] && d>slack[j])                    d = slack[j] ;            }            FF(j , M){                if( sx[j] )                    lx[j] -= d ;            }            FF(j , M){                if( sy[j] )                    ly[j] += d ;                else                    slack[j] -= d ;            }        }    }    int res = 0 ;    FF(i , M)        res += w[ match[i] ][i] ;    return res ;}int main(){    int a ;    while(scanf("%d%d",&N,&M) == 2){        CC(w, 0 ) ;        FF(i , N){            FF(j , M){                scanf("%d",&a) ;                w[i][j] = a * 100 ;            }        }        int num = 0 ;        FF(i , N){            scanf("%d",&a);            a--;            num += w[i][a] ;            w[i][a] ++ ;        }        int res = KM() ;        printf("%d %d\n",N-res%100,res/100-num/100);    }    return 0 ;}



原创粉丝点击