zoukankan      html  css  js  c++  java
  • KM算法及其应用

      在二分图匹配中有最大匹配问题,使用匈牙利算法或者网络流相关算法解决,如果给每条边增加一个权值,求权值和最大的匹配方案就叫做最大权匹配问题。其实之前所说的最大匹配就是权值为1的最大权匹配。

      求最大权完备匹配常用的方法是Kuhn-Munkres算法(简称KM算法),其主要思想就是通过顶标将求最大权匹配问题转化为求解最大匹配问题。算法的大致思路是任意构造一个可行顶标(比如Y结点顶标为0,X结点的顶标为它出发所有边的最大权值),然后求相等子图的最大匹配,如果存在完美匹配,算法终止,否则修改顶标使得相等子图的边变多,有更大的机会存在完美匹配。

      下面以题为例,给出时间复杂度O(n4)的算法。

    题目链接:

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

      1 /*
      2 问题 
      3 将任意的两个字符串进行匹配,使得匹配后权值和最大
      4 
      5 解题思路
      6 将任意的字符串的权值计算出来,使用KM算法即可。 
      7 */ 
      8 #include<cstdio>
      9 #include<cstring>
     10 #include<algorithm>
     11 using namespace std;
     12 
     13 const int maxn=210;
     14 int W[maxn][maxn],n;
     15 char s[maxn][1100];
     16 int lx[maxn],ly[maxn];
     17 int left[maxn];
     18 bool S[maxn],T[maxn];
     19 int len[maxn];
     20 
     21 void presolve();
     22 int KM();
     23 bool match(int i);
     24 void update();
     25 
     26 int main()
     27 {
     28     int i,j;
     29     while(scanf("%d",&n) != EOF)
     30     {
     31         for(i=1;i<=n;i++)
     32         {
     33             scanf("%s",s[i]);
     34             len[i]=strlen(s[i]);
     35         }
     36         presolve();
     37 
     38         printf("%d
    ",KM());
     39     }
     40 }
     41 
     42 bool match(int i)
     43 {
     44     S[i]=true;
     45     for(int j=1;j<=n;j++) if(lx[i]+ly[j] == W[i][j] && !T[j]){
     46         T[j]=true;
     47         if(!left[j] || match(left[j])){
     48             left[j]=i;
     49             return true;
     50         }
     51     }
     52     return false;
     53 }
     54 
     55 void update()
     56 {
     57     int a= 1<<30;
     58     for(int i=1; i<=n; i++){
     59         if(S[i]){
     60             for(int j=1;j<=n;j++){
     61                 if(!T[j]){
     62                     a = min(a,lx[i]+ly[j] - W[i][j]);
     63                 }
     64             }
     65         }
     66     }
     67     
     68     for(int i=1;i<=n;i++){
     69         if(S[i])    lx[i] -= a;
     70         if(T[i])    ly[i] += a;
     71     }
     72 }
     73 
     74 int KM()
     75 {
     76     for(int i=1;i<=n;i++){
     77         left[i] = lx[i] = ly[i] = 0;
     78         for(int j=1; j<=n; j++)
     79             lx[i]=max(lx[i],W[i][j]);    
     80     }
     81     
     82     for(int i=1; i<=n; i++){
     83         for(;;){
     84             for(int j=1;j<=n;j++){
     85                 S[j]=T[j]=0;
     86             }
     87             if(match(i)) break;
     88             else update();
     89         }
     90     }
     91     
     92     int ans=0;
     93     for(int i=1;i<=n;i++)
     94         ans += W[left[i]][i];
     95     return ans;
     96 }
     97 
     98 void presolve()
     99 {
    100     int i,j,k,p1,p2,cnt;
    101     for(i=1;i<=n;i++)
    102     {
    103         for(j=1;j<=n;j++)
    104         {
    105             if(i==j)
    106             {
    107                 W[i][j]=0;
    108                 continue ;
    109             }
    110             
    111             cnt=0;
    112             p1=len[i]-1;
    113             p2=0;
    114             while(1)
    115             {
    116                 if(s[i][p1]==s[j][p2]) cnt++;
    117                 else break ;
    118                 p1--,p2++;
    119                 if(p1<0 || p2>=len[j]) break ;
    120             }
    121             W[i][j]=cnt;
    122         }
    123     }
    124 }
  • 相关阅读:
    玩不转云计算的架构
    从《从架构的角度看,如何写好代码?》中来看如何编写单元测试代码
    换种形式工作
    程序员下一门要学的编程语言Swift
    从钉钉微应用定制化导航栏看如何实现Hybrid App开发框架
    纯灌水Linus主义
    kFreeBSD有活过来的迹象?UbuntuBSD
    架构的重要性
    MacOS下如何进行Git的冲突(Conflict)处理
    [转]以Facebook为案例剖析科技公司应有的工具文化
  • 原文地址:https://www.cnblogs.com/wenzhixin/p/9053758.html
Copyright © 2011-2022 走看看