[POJ2195]Going Home(带权最大匹配,KM,最小费用流)
题目链接:http://poj.org/problem?id=2195
题意:给个图,m代表人H代表房子。每一个m要有一个H,代价是曼哈顿距离。问让所有m找到房子的最小花费。
可以直接枚举m和H建二分图跑KM。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <cassert> 8 #include <cstdio> 9 #include <bitset> 10 #include <vector> 11 #include <deque> 12 #include <queue> 13 #include <stack> 14 #include <ctime> 15 #include <set> 16 #include <map> 17 #include <cmath> 18 19 using namespace std; 20 21 const int maxn = 310; 22 const int inf = 0x3f3f3f3f; 23 int nx,ny; 24 int G[maxn][maxn]; 25 int linker[maxn],lx[maxn],ly[maxn]; 26 int slack[maxn]; 27 bool visx[maxn],visy[maxn]; 28 29 bool dfs(int x) { 30 visx[x] = true; 31 for(int y = 0; y < ny; y++) { 32 if(visy[y])continue; 33 int tmp = lx[x] + ly[y] - G[x][y]; 34 if(tmp == 0) { 35 visy[y] = true; 36 if(linker[y] == -1 || dfs(linker[y])) { 37 linker[y] = x; 38 return true; 39 } 40 } 41 else if(slack[y] > tmp) 42 slack[y] = tmp; 43 } 44 return false; 45 } 46 int km() { 47 memset(linker,-1,sizeof(linker)); 48 memset(ly,0,sizeof(ly)); 49 for(int i = 0;i < nx;i++) { 50 lx[i] = -inf; 51 for(int j = 0;j < ny;j++) 52 if(G[i][j] > lx[i]) 53 lx[i] = G[i][j]; 54 } 55 for(int x = 0;x < nx;x++) { 56 for(int i = 0;i < ny;i++) 57 slack[i] = inf; 58 while(true) { 59 memset(visx,false,sizeof(visx)); 60 memset(visy,false,sizeof(visy)); 61 if(dfs(x))break; 62 int d = inf; 63 for(int i = 0;i < ny;i++) 64 if(!visy[i] && d > slack[i]) 65 d = slack[i]; 66 for(int i = 0;i < nx;i++) 67 if(visx[i]) 68 lx[i] -= d; 69 for(int i = 0;i < ny;i++) { 70 if(visy[i])ly[i] += d; 71 else slack[i] -= d; 72 } 73 } 74 } 75 int res = 0; 76 for(int i = 0;i < ny;i++) 77 if(linker[i] != -1) 78 res += G[linker[i]][i]; 79 return res; 80 } 81 82 typedef pair<int,int> pii; 83 char mp[maxn][maxn]; 84 int n, m; 85 vector<pii> h, p; 86 87 int main() { 88 // freopen("in", "r", stdin); 89 while(~scanf("%d%d",&n,&m) && n+m) { 90 memset(mp, 0, sizeof(mp)); 91 h.clear(); p.clear(); 92 for(int i = 1; i <= n; i++) { 93 scanf("%s", mp[i]+1); 94 } 95 for(int i = 1; i <= n; i++) { 96 for(int j = 1; j <= m; j++) { 97 if(mp[i][j] == 'H') h.push_back(pii(i, j)); 98 else if(mp[i][j] == 'm') p.push_back(pii(i, j)); 99 } 100 } 101 memset(G, 0, sizeof(G)); 102 nx = h.size(); ny = p.size(); 103 for(int i = 0; i < h.size(); i++) { 104 for(int j = 0; j < p.size(); j++) { 105 int dis = abs(h[i].first - p[j].first) + abs(h[i].second - p[j].second); 106 G[i][j] = -dis; 107 } 108 } 109 printf("%d\n", -km()); 110 } 111 return 0; 112 }
也可以用最小费用流建模。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <cassert> 8 #include <cstdio> 9 #include <bitset> 10 #include <vector> 11 #include <deque> 12 #include <queue> 13 #include <stack> 14 #include <ctime> 15 #include <set> 16 #include <map> 17 #include <cmath> 18 19 using namespace std; 20 21 typedef long long LL; 22 typedef struct Node { 23 int u, v, next; 24 LL c, w; 25 }Node; 26 const int maxn = 20010; 27 const int maxm = 40010; 28 const LL mod = 0x3f3f3f3fLL; 29 const LL inf = (1LL<<55); 30 int tot, head[maxn]; 31 LL dist[maxn]; 32 LL cost, flow; 33 Node e[maxm]; 34 int pre[maxn]; 35 bool visit[maxn]; 36 queue<int> Q; 37 int S, T, N; 38 39 void init() { 40 S = T = N = 0; 41 memset(head, -1, sizeof(head)); 42 tot = 0; 43 } 44 45 void adde(int u, int v, LL c, LL w) { 46 e[tot].u = u; e[tot].v = v; e[tot].c = c; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++; 47 e[tot].u = v; e[tot].v = u; e[tot].c = 0; e[tot].w = -w; e[tot].next = head[v]; head[v] = tot++; 48 } 49 bool spfa(int s, int t, int n) { 50 int i; 51 for(i = 0; i <= n; i++) { 52 dist[i] = inf; 53 visit[i] = 0; 54 pre[i] = -1; 55 } 56 while(!Q.empty()) Q.pop(); 57 Q.push(s); 58 visit[s] = true; 59 dist[s] = 0; 60 pre[s] = -1; 61 while(!Q.empty()) { 62 int u = Q.front(); 63 visit[u] = false; 64 Q.pop(); 65 for(int j = head[u]; j != -1; j = e[j].next) { 66 if(e[j].c > 0 && dist[u] + e[j].w < dist[e[j].v]) { 67 dist[e[j].v] = dist[u] + e[j].w; 68 pre[e[j].v] = j; 69 if(!visit[e[j].v]) { 70 Q.push(e[j].v); 71 visit[e[j].v] = true; 72 } 73 } 74 } 75 } 76 if(dist[t] == inf) return false; 77 else return true; 78 } 79 LL ChangeFlow(int t) { 80 LL det = mod; 81 int u = t; 82 while(~pre[u]) { 83 u = pre[u]; 84 det = min(det, e[u].c); 85 u = e[u].u; 86 } 87 u = t; 88 while(~pre[u]) { 89 u = pre[u]; 90 e[u].c -= det; 91 e[u ^ 1].c += det; 92 u = e[u].u; 93 } 94 return det; 95 } 96 LL MinCostFlow(int s, int t, int n) { 97 LL mincost, maxflow; 98 mincost = maxflow = 0; 99 while(spfa(s, t, n)) { 100 LL det = ChangeFlow(t); 101 mincost += det * dist[t]; 102 maxflow += det; 103 } 104 cost = mincost; 105 flow = maxflow; 106 return mincost; 107 } 108 109 typedef pair<int,int> pii; 110 char mp[111][111]; 111 int n, m; 112 vector<pii> h, p; 113 114 int main() { 115 // freopen("in", "r", stdin); 116 while(~scanf("%d%d",&n,&m) && n+m) { 117 init(); 118 memset(mp, 0, sizeof(mp)); 119 h.clear(); p.clear(); 120 for(int i = 1; i <= n; i++) { 121 scanf("%s", mp[i]+1); 122 } 123 for(int i = 1; i <= n; i++) { 124 for(int j = 1; j <= m; j++) { 125 if(mp[i][j] == 'H') h.push_back(pii(i, j)); 126 else if(mp[i][j] == 'm') p.push_back(pii(i, j)); 127 } 128 } 129 S = 0, T = h.size() + p.size() + 1, N = T + 1; 130 for(int i = 0; i < h.size(); i++) adde(S, i+1, 1, 0); 131 for(int i = 0; i < p.size(); i++) adde(h.size()+i+1, T, 1, 0); 132 for(int i = 0; i < h.size(); i++) { 133 for(int j = 0; j < p.size(); j++) { 134 int dis = abs(h[i].first - p[j].first) + abs(h[i].second - p[j].second); 135 int hi = i + 1; 136 int pi = h.size() + j + 1; 137 adde(hi, pi, 1, (LL)dis); 138 } 139 } 140 cout << MinCostFlow(S, T, N) << endl; 141 } 142 return 0; 143 }