题目链接:uva 10746 - Crime Wave - The Sequel
题目大意:自从银行被抢之后,警局为每个银行都安排了一个警察,现在有n个银行和m警察,给出每个警察到达各个银行的时间,问说怎么样安排人手,可以使的警察到达银行的平均时间最小。
解题思路:网络流的最小费用最大流,起点s与m个警察相连,容量为1,费用为0;n个银行与汇点t相连,容量为1,费用为0;然后就是警察和银行之间的边,为有向边,警察指向银行,费用为时间。然后建好图就是单纯的费用流问题。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;
#define min(a,b) (a)<(b)?(a):(b)
const int N = 205;
const int T = 100;
const int INF = 1 << 30;
int n, m, tmp, g[N][N], f[N][N];
double cost[N][N];
vector<int> v[N];
void add(int x, int y) {
g[x][y]++;
v[x].push_back(y);
v[y].push_back(x);
}
void init() {
tmp = 200;
memset(g, 0, sizeof(g));
memset(f, 0, sizeof(f));
memset(cost, 0, sizeof(cost));
for (int i = 0; i < N; i++)
v[i].clear();
for (int i = 1; i <= n; i++) {
add(0, i + T);
add(i + T, i);
for (int j = 1; j <= m; j++) {
add(i, j + n + T);
}
}
for (int i = 1; i <= m; i++) {
add(i + n + T, i + n);
add(i + n, tmp);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%lf", &cost[i][j + n + T]);
cost[j + n + T][i] = -cost[i][j + n + T];
}
}
}
void solve() {
queue<int> que;
double ans = 0, d[N];
int c, flow = 0, path[N], vis[N];
while (1) {
for (int i = 0; i <= tmp; i++)
d[i] = (i == 0) ? 0 : INF;
memset(path, 0, sizeof(path));
memset(vis, 0, sizeof(vis));
que.push(0);
vis[0] = 1;
while (!que.empty() ) {
c = que.front(), que.pop();
vis[c] = 0;
int top = v[c].size();
for (int i = 0; i < top; i++) {
if (g[c][v[c][i]] > f[c][v[c][i]] && d[v[c][i]] - d[c] - cost[c][v[c][i]] > 1e-6) {
d[v[c][i]] = d[c] + cost[c][v[c][i]];
path[v[c][i]] = c;
if ( vis[v[c][i]] == 0) {
que.push(v[c][i]);
vis[v[c][i]] = 1;
}
}
}
}
if (INF - d[tmp] < 1e-6) break;
int t = INF;
for (int i = tmp; i; i = path[i]) t = min(g[path[i]][i] - f[path[i]][i], t);
flow += t;
ans += t * d[tmp];
for (int i = tmp; i; i= path[i]) {
f[path[i]][i] += t;
f[i][path[i]] -= t;
}
}
printf("%.2lf\n", ans / n + 0.001);
}
int main () {
while (scanf("%d%d", &n, &m), n + m) {
init();
solve();
}
return 0;
}