题意:给个矩阵,矩阵里有一些人和房子(人数和房子数相等),一个人只进一个房子(可以路过房子而不进),每走一步花费1美金,求所有人都进入房子的最小花费,这是典型的二分图带权匹配问题。
这题就是建图有点麻烦,但绝不抽象,直接用BFS遍历每个人到所有房子的距离,遍历出一个就拉一条人到房子有向边,建完图就是套模板了。
注意:KM算法是求最大权匹配的,要求最小权就要把所有边取相反数,最后结果再取相反数,但这只能是完美匹配,不完美匹配还要变一些。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #include<iostream> 6 #define maxn 500 7 8 using namespace std; 9 10 11 char group[101][101]; 12 int index[101][101]; 13 struct pos 14 { 15 int x,y; 16 }people[maxn],house[maxn]; 17 struct edge 18 { 19 int to,cap; 20 }; 21 vector<edge> g[maxn]; 22 int a,b,sum_m,sum_h; 23 24 const int mir[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; 25 int vis[101][101]; 26 struct step 27 { 28 int x,y,s; 29 }; 30 void init() 31 { 32 sum_m=sum_h=0; 33 memset(people,0,sizeof(people)); 34 memset(house,0,sizeof(house)); 35 memset(index,0,sizeof(index)); 36 for(int i=0;i<maxn;i++) 37 g[i].clear(); 38 } 39 void add_edge(int from,int to,int cap) 40 { 41 g[from].push_back((edge){to,cap}); 42 } 43 void bfs(int sx,int sy,int ex,int ey) 44 { 45 memset(vis,0,sizeof(vis)); 46 step now,next; 47 queue<step> q; 48 now.x=sx,now.y=sy,now.s=0; 49 vis[sx][sy]=1; 50 q.push(now); 51 while(!q.empty()) 52 { 53 now=q.front(); 54 q.pop(); 55 if(now.x==ex&&now.y==ey) 56 { 57 add_edge(index[sx][sy],index[now.x][now.y],~now.s+1); 58 return; 59 } 60 for(int i=0;i<4;i++) 61 { 62 int x=now.x+mir[i][0]; 63 int y=now.y+mir[i][1]; 64 if(x>=0&&y>=0&&x<a&&y<b) 65 { 66 if(!vis[x][y]) 67 { 68 vis[x][y]=1; 69 next.x=x,next.y=y,next.s=now.s+1; 70 q.push(next); 71 } 72 } 73 } 74 } 75 } 76 int x[maxn], y[maxn], link[maxn],sx[maxn], sy[maxn]; 77 int slack; 78 int DFS(int t) 79 { 80 int i, tmp; 81 sx[t] = 1; 82 for (i = 0; i < g[t].size(); i++) 83 { 84 edge e=g[t][i]; 85 if (!sy[e.to]) 86 { 87 tmp = x[t] + y[e.to] - e.cap; 88 if (tmp == 0) 89 { 90 sy[e.to] = 1; 91 if (link[e.to] == -1 || DFS(link[e.to])) 92 { 93 link[e.to] = t; 94 return 1; 95 } 96 } 97 else if (tmp < slack) 98 slack = tmp; 99 } 100 } 101 return 0; 102 } 103 void KM() 104 { 105 int i, j; 106 for(int w=0;w<sum_m;w++) 107 { 108 x[w]=0; 109 for(int v=0;v<g[w].size();v++) 110 { 111 if(g[w][v].cap>x[w]) 112 x[w]=g[w][v].cap; 113 } 114 } 115 for (j = 0; j < sum_h; j++) 116 { 117 y[j] = 0; 118 } 119 memset(link, -1, sizeof(link)); 120 for (i = 0; i < sum_m; i++) 121 { 122 while (1) 123 { 124 memset(sx, 0, sizeof(sx)); 125 memset(sy, 0, sizeof(sy)); 126 slack = 0xfffffff; 127 if (DFS(i)) break; 128 for (j = 0; j < sum_m; j++) 129 { 130 if (sx[j]) 131 x[j] -= slack; 132 } 133 for (j = 0; j < sum_h; j++) 134 { 135 if (sy[j]) 136 y[j] += slack; 137 } 138 } 139 } 140 } 141 142 int main() 143 { 144 while(scanf("%d%d",&a,&b)!=EOF,a&&b) 145 { 146 getchar(); 147 init(); 148 for(int i=0;i<a;i++) 149 { 150 gets(group[i]); 151 for(int j=0;j<b;j++) 152 { 153 if(group[i][j]=='m') 154 { 155 people[sum_m].x=i; 156 people[sum_m].y=j; 157 index[i][j]=sum_m; 158 sum_m++; 159 } 160 else if(group[i][j]=='H') 161 { 162 house[sum_h].x=i; 163 house[sum_h].y=j; 164 index[i][j]=sum_h; 165 sum_h++; 166 } 167 } 168 } 169 for(int n=0;n<sum_m;n++) 170 { 171 for(int m=0;m<sum_h;m++) 172 { 173 bfs(people[n].x,people[n].y,house[m].x,house[m].y); 174 } 175 } 176 /* for(int i=0;i<sum_m;i++) 177 { 178 cout<<i<<" "; 179 for(int j=0;j<g[i].size();j++) 180 cout<<g[i][j].to<<" "<<g[i][j].cap<<endl; 181 }*/ 182 KM(); 183 int ans=0; 184 int coun = 0,t=0; 185 for (int i = 0; i < sum_h; i++) 186 { 187 t = link[i]; 188 if (t >= 0) 189 { 190 coun ++; 191 ans += g[t][i].cap; 192 } 193 } 194 printf("%d\n",~ans+1); 195 } 196 return 0; 197 }