zoukankan      html  css  js  c++  java
  • poj 2195 KM算法

    n个人要回到n个屋子,要求最小的花费。

    KM算法可以求二分图最大权匹配,求最少花费可以先对距离取负数,求最大,再取负数即可。

    ps:km算法看的还不是很懂啊《《《》》

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 
      8 #define MAXN 110
      9 #define inf 999999999
     10 
     11 struct point
     12 {
     13     int x,y;
     14 }pos_k[MAXN],pos_h[MAXN];
     15 int n,m;
     16 int w[MAXN][MAXN];
     17 int lx[MAXN],ly[MAXN];
     18 int linky[MAXN];
     19 int visx[MAXN],visy[MAXN];
     20 int slack[MAXN];
     21 int nx,ny;
     22 
     23 bool find(int x)
     24 {
     25     visx[x] = true;
     26     for(int y = 1; y <=ny; y++)
     27     {
     28         if(visy[y])
     29             continue;
     30         int t = lx[x] + ly[y] - w[x][y];
     31         if(t==0)
     32         {
     33             visy[y] = true;
     34             if(linky[y]==-1 || find(linky[y]))
     35             {
     36                 linky[y] = x;
     37                 return true;        //找到增广轨
     38             }
     39         }
     40         else if(slack[y] > t)
     41             slack[y] = t;
     42     }
     43     return false;                   //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
     44 }
     45 
     46 int KM()                //返回最优匹配的值
     47 {
     48     int i,j;
     49     memset(linky,-1,sizeof(linky));
     50     memset(ly,0,sizeof(ly));
     51     for(i = 1; i <=nx; i++)
     52     {
     53         lx[i] = -inf;
     54          for(j = 1; j <=nx; j++)
     55             if(w[i][j] > lx[i])
     56                 lx[i] = w[i][j];
     57     }
     58 
     59     for(int x = 1; x <=nx; x++)
     60     {
     61         for(i = 1; i <=nx; i++)
     62             slack[i] = inf;
     63         while(true)
     64         {
     65             memset(visx,0,sizeof(visx));
     66             memset(visy,0,sizeof(visy));
     67             if(find(x))                     //找到增广轨,退出
     68                 break;
     69             int d = inf;
     70             for(i = 1; i <=nx; i++)          //没找到,对l做调整(这会增加相等子图的边),重新找
     71             {
     72                 if(!visy[i] && d > slack[i])
     73                     d = slack[i];
     74             }
     75             for(i = 1; i <=nx; i++)
     76             {
     77                 if(visx[i])
     78                     lx[i] -= d;
     79             }
     80             for(i = 1; i <=ny; i++)
     81             {
     82                 if(visy[i])
     83                      ly[i] += d;
     84                 else
     85                     slack[i] -= d;
     86             }
     87         }
     88     }
     89     int result = 0;
     90     for(i = 1; i <=ny; i++)
     91     if(linky[i]>-1)
     92         result += w[linky[i]][i];
     93     return result;
     94 }
     95 
     96 int dist(point a,point b)
     97 {
     98     int dis=0;
     99     dis+=(a.x-b.x)>0?(a.x-b.x):(b.x-a.x);
    100     dis+=(a.y-b.y)>0?(a.y-b.y):(b.y-a.y);
    101     return dis;
    102 }
    103 
    104 bool read()
    105 {
    106     scanf("%d%d",&n,&m);
    107     getchar();
    108     char buf[MAXN];
    109     if(n+m==0)
    110         return false;
    111     nx=0,ny=0;
    112     for(int i=1;i<=n;i++)
    113     {
    114         gets(buf);
    115         for(int j=0;j<m;j++)
    116         {
    117             if(buf[j]=='H')
    118             {
    119                 pos_h[ny].x=i;
    120                 pos_h[ny++].y=j+1;
    121             }
    122             else if(buf[j]=='m')
    123             {
    124                 pos_k[nx].x=i;
    125                 pos_k[nx++].y=j+1;
    126             }
    127         }
    128     }
    129     for(int i=0;i<nx;i++)
    130         for(int j=0;j<ny;j++)
    131         {
    132             w[i+1][j+1]=-dist(pos_k[i],pos_h[j]);//取负
    133         }
    134     return true;
    135 }
    136 
    137 int main()
    138 {
    139     while(read())
    140     {
    141         printf("%d\n",-KM());
    142     }
    143     return 0;
    144 }

     

  • 相关阅读:
    org.dom4j.Document相关操作api
    生成excel
    Maven
    Excel操作
    常用正则
    csv
    导出txt
    Map中的key值按字典排序,客户端发送http请求
    HmacSHA256签名加Base64编码加URL编码
    5.1SpringAOP-基础(装饰者,静态代理,JDKD动态代理,CGLIB动态代理)
  • 原文地址:https://www.cnblogs.com/Missa/p/2705595.html
Copyright © 2011-2022 走看看