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 }