zoukankan      html  css  js  c++  java
  • 完美匹配【KM算法hdu总结】

    转载出处:http://972169909-qq-com.iteye.com/blog/1184514


    题目链接:http://acm.hdu.edu.cn/diy/contest_show.php?cid=12698.iteye.com/blog/1184514

    题目链接:http://acm.hdu.edu.cn/diy/contest_show.php?cid=12698

    我的链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=17728#overview



    首先献上模板:

    C++代码  收藏代码
    1. #define M 505  
    2. #define inf 0x3fffffff  
    3. bool sx[M], sy[M];  
    4. int match[M], w[M][M], n, m, d, lx[M], ly[M];  
    5. //n:左集元素个数; m:右集元素个数  
    6. void init ()  
    7. {  
    8.     memset (w, 0, sizeof(w));    //不一定要,求最小值一般要初始化为负无穷!  
    9. }  
    10.   
    11. bool dfs (int u)  
    12. {  
    13.     int v; sx[u] = true;  
    14.     for (v = 0; v < m; v++)  
    15.     {  
    16.         if (!sy[v] && lx[u]+ly[v]==w[u][v])  
    17.         {  
    18.             sy[v] = true;  
    19.             if (match[v] == -1 || dfs (match[v]))  
    20.             {  
    21.                 match[v] = u;  
    22.                 return true;  
    23.             }  
    24.         }  
    25.     }  
    26.     return false;  
    27. }  
    28.   
    29. int KM ()  
    30. {  
    31.     int i, j, k, sum = 0;  
    32.     memset (ly, 0, sizeof(ly));  
    33.     for (i = 0; i < n; i++)  
    34.     {  
    35.         lx[i] = -inf;  
    36.         for (j = 0; j < m; j++)  
    37.             if (lx[i] < w[i][j])  
    38.                 lx[i] = w[i][j];  
    39.     }  
    40.     memset (match, -1, sizeof(match));  
    41.     for (i = 0; i < n; i++)  
    42.     {  
    43.         while (1)  
    44.         {  
    45.             memset (sx, falsesizeof(sx));  
    46.             memset (sy, falsesizeof(sy));  
    47.             if (dfs (i))  
    48.                 break;  
    49.             d = inf;  
    50.             for (j = 0; j < n; j++)  
    51.                 if (sx[j])  
    52.                     for (k = 0; k < m; k++)  
    53.                         if (!sy[k])  
    54.                             d = min (d, lx[j]+ly[k]-w[j][k]);  
    55.             if (d == inf)    //找不到完美匹配  
    56.                 return -1;  
    57.             for (j = 0; j < n; j++)  
    58.                 if (sx[j])  
    59.                     lx[j] -= d;  
    60.             for (j = 0; j < m; j++)  
    61.                 if (sy[j])  
    62.                     ly[j] += d;  
    63.         }  
    64.     }  
    65.     for (i = 0; i < m; i++)  
    66.         if (match[i] > -1)  
    67.             sum += w[match[i]][i];  
    68.     return sum;  
    69. }  

    第一题:http://acm.hdu.edu.cn/showproblem.php?pid=2255
    直接输入w[i][j]边权值建图套模板就可以了

    第二题:http://acm.hdu.edu.cn/showproblem.php?pid=1533
    将m的坐标记录到左集,h的坐标记录到右集,w[i][j]表示第i个m到第j个h的距离
    w[i][j]=△x+△y 然后因为是求最小值,而KM是求最大值
    所以只要这样:w[i][j] = -w[i][j]建图再套模板输出【-sum】就ok!

    第三题:http://acm.hdu.edu.cn/showproblem.php?pid=1853
    直接建图,注意有重边哦!
    if (-c > w[a][b])
        w[a][b] = -c;

    当木有完美匹配输出-1

    第四题:http://acm.hdu.edu.cn/showproblem.php?pid=3488
    跟第三题几乎一样

    第五题:http://acm.hdu.edu.cn/showproblem.php?pid=3435
    跟第三题代码基本上一样,只是要双向建图,也有重边

    第六题:http://acm.hdu.edu.cn/showproblem.php?pid=2426
    左集是学生,右集是房子,注意 w[i][j] < 0 不可匹配,最后无法完美匹配输出-1

    第七题:http://acm.hdu.edu.cn/showproblem.php?pid=2853
    题目要求匹配最大值和至少要改变多少个原有匹配
    思路:让原有匹配更有优势就可以了
    实现:所有权值扩大100倍,原有匹配【例如a匹配b】w[a][b]++
    设结果是res
    最大值:res/100
    至少改变个数:n - res%100


    第八题:http://acm.hdu.edu.cn/showproblem.php?pid=3718
    题目求的是两字符串的最大相似度
    思路:因为第一个串的一种字母只能匹配第二个串的一种字母,所以可以转化为求
    【字母的最大匹配值/n】
    建图:【例】



    第九题:http://acm.hdu.edu.cn/showproblem.php?pid=3722
    直接按题目要求建图,注意跟自己匹配的值是0,w[i][i]=0

    第十题:http://acm.hdu.edu.cn/showproblem.php?pid=3395
    直接按题目要求建图就可以了

    第十一题:http://acm.hdu.edu.cn/showproblem.php?pid=2282
    建图:多余的1分别跟所有的0算出最小距离,例如3,多了2个1,要把他们跟所有0匹配,左集是1,右集是这n个数【限制匹配条件(=0)就可以了】
    左集个数为m,表示有多少个1需要移动
    m = 0;
    for (i = 0; i < n; i++)
    {
        if (a[i] > 1)
        {
            for (j = 1; j < a[i]; j++)
            {
                for (k = 0; k < n; k++)
                    if (a[k] == 0)
                        w[m][k] = -min (abs(k-i), n-abs(k-i));
                m++;
            }
        }
    }


    第十二题:http://acm.hdu.edu.cn/showproblem.php?pid=2813
    这题比较容易超时……
    用STL的map把字符串映射为序号
    m1.clear();
    m2.clear();
    k1 = k2 = 1;
    while (q--)
    {
        scanf ("%s%s%d", s, p, &x);
        string a(s);
        string b(p);
        if (m1[a] == 0)
            m1[a] = k1++;
        if (m2[b] == 0)
            m2[b] = k2++;
        w[m1[a]][m2[b]] = -x;
    }


    第十三题:http://acm.hdu.edu.cn/showproblem.php?pid=2448
    这题要读懂题目意思!
    题意:n艘船要分别回到n个码头,另外有m个采矿点,一开始n艘船所在采矿点已经给出,采矿点与采矿点之间给出k条路【双向的】,码头与采矿点之间给出p条路,由于船进入码头后就不会出来,所以这条路是单向的!
    实现:最短路+KM

    第十四题:http://acm.hdu.edu.cn/showproblem.php?pid=2236
    题意:n×n的矩阵中,没行找一个元素,每个元素之间不可同列,求这n个元素的最大值-最小值的最小差
    思路:暴力枚举差值【由于元素的值0<= x <=100, 差值的范围也只能是[0,100]】
    匈牙利检验就可以了
    bool KM (int low, int high)
    {
        int i;
        memset (match, -1, sizeof(match));
        for (i = 0; i < n; i++)
        {
            memset (vis, false, sizeof(vis));
            if (!dfs (i, low, high))
                return false;
        }
        return true;
    }


    第十五题:http://acm.hdu.edu.cn/showproblem.php?pid=3315
    默认匹配是w[i][i]
    si打赢xj,w[i][j] = v[i]
    如果si输了,w[i][j] = -v[i]
    所有权值扩大100倍,w[i][i]++优先匹配
    相似度=(res%100*100/n)%

  • 相关阅读:
    在QT函数中返回一个数组/把一个数组传参给函数
    QT储存内容到指定的文件内
    QT对linux下/sys/class/gpio中的gpio的控制
    QT 线程的暂停和继续
    QT的close和系统的close冲突
    画动态曲线另一种方式方式
    QT关于iCCP警告去除
    ps两张图片合在一起
    ps 做动态图
    解决MFC中因控件类多次Attch造成的销毁窗口过程中CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); ASSERT(pWnd != NULL); 断言失败的问题
  • 原文地址:https://www.cnblogs.com/freezhan/p/2950445.html
Copyright © 2011-2022 走看看