题目大意:
有n所银行,有m辆巡警车,给出巡警车到各个银行所需要的距离,问平均最小的距离是多少。
思路:
最小费用最大流的问题。
构造一个超级源点,然后连接边到各辆巡警车,巡警车与各所银行相连接,容量为1,费用为k。先求出费用最小的路,然后在费用最小的路上增流
代码:
#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>
#include <queue>
int n,m;
#define eps 1e-6
const int MAX = 102;
const int INF = 0x3f3f3f3f;
struct node {
int u,v;
double cost;
int cap;
int flow;
int ne;
}e[10000];
int first[MAX],p[MAX];
double dis[MAX];
int vis[MAX];
int edgenum;
int F;
int s,t;
double c;
void add(int u,int v,int cap,double w) {
e[edgenum].u = u;
e[edgenum].v = v;
e[edgenum].flow = 0;
e[edgenum].cap = cap;
e[edgenum].cost = w;
e[edgenum].ne = first[u];
first[u] = edgenum++;
e[edgenum].u = v;
e[edgenum].v = u;
e[edgenum].flow = 0;
e[edgenum].cap = 0;
e[edgenum].cost = -w;
e[edgenum].ne = first[v];
first[v] = edgenum++;
}
void EK() {
queue<int> q;
F = 0;
c = 0;
while(1) {
for(int i = 0; i <= t; i++)
dis[i] = INF;
dis[0] = 0;
memset(vis,0,sizeof(vis));
memset(p,-1,sizeof(p));
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for(int k = first[u]; k != -1; k = e[k].ne) {
int v = e[k].v;
if(e[k].cap > e[k].flow && dis[v] > dis[u] + e[k].cost + eps) {
dis[v] = dis[u] + e[k].cost;
p[v] = k;
if(!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
if(dis[t] == INF)
break;
int a = INF;
for(int u = p[t];u != -1; u = p[e[u^1].v])
a = min(a,e[u].cap - e[u].flow);
for(int u = p[t];u != -1; u = p[e[u^1].v]) {
e[u].flow += a;
e[u ^1].flow -=a;
}
c += dis[t] *(double)a;//因为a肯定为1,所以无所谓有没有乘
F += a;
}
}
int main() {
double k;
while(scanf("%d%d",&n,&m) && n && m) {
edgenum = 0;
s = 0;
t = n + m + 1;
memset(first,-1,sizeof(first));
for(int i = 1; i <= m ; i++) {
add(0,i,1,0);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int u = j;
int v = m + i;
scanf("%lf",&k);
add(u,v,1,k);
}
}
for(int i = m + 1; i <= n + m; i++) {
add(i,t,1,0);
}
EK();
printf("%.2f\n",c/n + eps);
}
return 0;
}