zoukankan      html  css  js  c++  java
  • 二分图最大带权匹配:KM算法

    二分图最大带权匹配。

    输入点的个数和各边权值,输出最大匹配的权值和。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4  
     5 using namespace std;
     6  
     7 const int N=310;
     8 const int INF=0x3f3f3f3f;
     9  
    10 int n,nx,ny;
    11 int linker[N],lx[N],ly[N],slack[N];  //lx,ly为顶标,nx,ny分别为x点集y点集的个数
    12 int visx[N],visy[N],w[N][N];
    13  
    14 int DFS(int x){
    15     visx[x]=1;
    16     for(int y=1;y<=ny;y++){
    17         if(visy[y])
    18             continue;
    19         int tmp=lx[x]+ly[y]-w[x][y];
    20         if(tmp==0){
    21             visy[y]=1;
    22             if(linker[y]==-1 || DFS(linker[y])){
    23                 linker[y]=x;
    24                 return 1;
    25             }
    26         }else if(slack[y]>tmp){ //不在相等子图中slack 取最小的
    27             slack[y]=tmp;
    28         }
    29     }
    30     return 0;
    31 }
    32  
    33 int KM(){
    34     int i,j;
    35     memset(linker,-1,sizeof(linker));
    36     memset(ly,0,sizeof(ly));
    37     for(i=1;i<=nx;i++)      //lx初始化为与它关联边中最大的
    38         for(j=1,lx[i]=-INF;j<=ny;j++)
    39             if(w[i][j]>lx[i])
    40                 lx[i]=w[i][j];
    41     for(int x=1;x<=nx;x++){
    42         for(i=1;i<=ny;i++)
    43             slack[i]=INF;
    44         while(1){
    45             memset(visx,0,sizeof(visx));
    46             memset(visy,0,sizeof(visy));
    47             if(DFS(x))  //若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
    48                 break;  //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
    49                         //方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
    50                         //所有在增广轨中的Y方点的标号全部加上一个常数d
    51             int d=INF;
    52             for(i=1;i<=ny;i++)
    53                 if(!visy[i] && d>slack[i])
    54                     d=slack[i];
    55             for(i=1;i<=nx;i++)
    56                 if(visx[i])
    57                     lx[i]-=d;
    58             for(i=1;i<=ny;i++)  //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
    59                 if(visy[i])
    60                     ly[i]+=d;
    61                 else
    62                     slack[i]-=d;
    63         }
    64     }
    65     int res=0;
    66     for(i=1;i<=ny;i++)
    67         if(linker[i]!=-1)
    68             res+=w[linker[i]][i];
    69     return res;
    70 }
    71  
    72 int main(){
    73  
    74     //freopen("input.txt","r",stdin);
    75  
    76     while(~scanf("%d",&n)){
    77         nx=ny=n;
    78         for(int i=1;i<=n;i++)
    79             for(int j=1;j<=n;j++)
    80                 scanf("%d",&w[i][j]);
    81         int ans=KM();
    82         printf("%d
    ",ans);
    83     }
    84     return 0;
    85 }
  • 相关阅读:
    LOJ-10096(强连通+bfs)
    LOJ-10095(缩点的特殊使用)
    LOJ-10094(强连通分量)
    LOJ-10092(最大半连通子图)
    【BZOJ3489】A simple rmq problem(KD-Tree)
    UVA10384 推门游戏 The Wall Pushers(IDA*)
    [SCOI2005]骑士精神(IDA*)
    浅谈A*算法
    【模板】K-D Tree
    【XSY1953】【BZOJ4012】【HNOI2015】开店(动态点分治)
  • 原文地址:https://www.cnblogs.com/St-Lovaer/p/11945378.html
Copyright © 2011-2022 走看看