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


    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 3
    2 1 3
    3 2 4
    1 26 2
    2 1 3
    2 3
    1 2 3
    1 2 3
    1 2

    Sample Output

    2 26
    1 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 110
    int 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-ans%100,ans/100-count/100);    
        }
        return 0;
    }
  • 相关阅读:
    lintcode69- Binary Tree Level Order Traversal- easy
    lintcode378- Convert Binary Search Tree to Doubly Linked Lis- medium
    lintcode448- Inorder Successor in Binary Search Tree- medium
    lintcode94- Binary Tree Maximum Path Sum- medium
    lintcode475- Binary Tree Maximum Path Sum II- medium
    *lintcode246- Binary Tree Path Sum II- easy
    lintcode376- Binary Tree Path Sum- easy
    lintcode619- Binary Tree Longest Consecutive Sequence III- medium
    lintcode614- Binary Tree Longest Consecutive Sequence II- medium
    gstreamer在Ubuntu下构建开发环境 分类: ffmpeg-SDL-VLC-Live555 2015-04-07 17:56 324人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/hellocheng/p/7360681.html
Copyright © 2020-2023  润新知