【二分图匹配入门专题1】O

来源:互联网 发布:图床源码 编辑:程序博客网 时间:2024/05/23 13:00
Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better. 
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij. 
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.

InputFor each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on. 
1<=N<=M<=50, 1<Eij<=10000. 
Your program should process to the end of file.OutputFor each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.Sample Input

3 32 1 33 2 41 26 22 1 32 31 2 31 2 31 2

Sample Output

2 261 2题意:给你一个n行m列的二维矩阵,i行到j列的权值为对应的数值,最后一行输入n个数,表示1~n已经连通的对应j列,问:怎样匹配能使改动的边数最小,并且是最优匹配,输出变动的边的总数和增加的匹配值。思路:我写这道题的第一反应就是把原来已经连通的边记录一下,每次求到可行边时判断是否便利过该点,如没有,总数增加,输入总数就行了  其余km,然而我的自信最终被一遍又一遍的wrong否定  后来看了题解才知道原来如此,新技能已经拯救不了我疲惫的大脑。。。。。  好困啊   写km都快写吐啦~~(转)以下转自别人博客,但我需要说明一点,k=n+1的话,能够处理n=1这种特殊情况

巧妙的思路:

因为我们要变动最小,所以对在原计划中的边要有一些特殊照顾,使得最优匹配时,尽量优先使用原计划的边,这样变化才能是最小的且不会影响原匹配。

根据这个思想,我们可以把每条边的权值扩大k倍,k要大于n。然后对原计划的边都+1。精华全在这里。我们来详细说明一下。

全部边都扩大了k倍,而且k比n大,这样,我们求出的最优匹配就是k倍的最大权值,只要除以k就可以得到最大权值。实现原计划的边加1,这样,在每次选择边时,这些变就 有了优势,就会优先选择这些边。假如原计划的h条边被选入了最优匹配中,这样,最优权值就是k倍的最大权值+k(原计划的每条边都+1)。但是k大于n的用意何在呢?我们发现假如原计划的边全部在匹配中,只会增加n,又n<k,所以除以k后不会影响最优匹配的最大权值之和,然后我们对k取余,就正好得到加入的原计划的边的个数。这时,我们只需要用总点数-加入的原计划的点数,就可以求得最小变动数了。


#include<stdio.h>#include<string.h>#define INF 0x3f3f3f3f#define N 110int n,m;int map[N][N];int linker[N],lx[N],ly[N];int visx[N],visy[N];int ans,count,nx,ny,num,d;int dfs(int x){    int y,tmp;    visx[x] = 1;    for(y = 1; y <= ny; y ++)    {        if(!visy[y])        {            tmp = lx[x] + ly[y] - map[x][y];            if(!tmp)            {                visy[y] = 1;                if(linker[y] == -1||dfs(linker[y]))                {                    linker[y] = x;                    return 1;                }            }            else if(d > tmp)                d = tmp;        }    }    return 0;}int KM(){    int sum,x,y,i,j;    memset(linker,-1,sizeof(linker));    memset(ly,0,sizeof(ly));    for(i = 1; i <= nx; i ++)        for(j = 1,lx[i] = -INF; j <= ny; j ++)            if(lx[i] < map[i][j])                lx[i] = map[i][j];                    for(x = 1; x <= nx; x ++)    {        while(1)        {            memset(visx,0,sizeof(visx));            memset(visy,0,sizeof(visy));            d = INF;            if(dfs(x))                break;            for(i = 1; i <= nx; i ++)                if(visx[i])                    lx[i] -= d;            for(j = 1; j <= ny; j ++)                if(visy[j])                    ly[j] += d;        }    }    sum = 0;    for(i = 1; i <= ny; i ++)        if(linker[i]!=-1)            sum += map[linker[i]][i];    return sum;}int main(){    int i,j;    while(scanf("%d%d",&n,&m)!=EOF)    {        nx = n;        ny = m;        num = 0;        memset(map,0,sizeof(map));        for(i = 1; i <= n; i ++)            for(j = 1; j <= m; j ++)            {                scanf("%d",&map[i][j]);                map[i][j]*=100;//妙啊妙啊             }                        count = 0;        for(i = 1; i <= n; i ++)        {            scanf("%d",&j);            count += map[i][j];            map[i][j] += 1;//巧妙         }        ans = KM();        printf("%d %d\n",n-ans%100,ans/100-count/100);        }    return 0;}

原创粉丝点击