BZOJ 1070 修车 【费用流】


Description

  同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

Input

  第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。

Output

  最小平均等待时间,答案精确到小数点后2位。

Sample Input

2 2
3 2
1 4

Sample Output

1.50

HINT

数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)


题解

这道题需要我们将顾客与工人匹配,容易想到费用流

我们源点S从顾客流入,通过一条路径到达T,使这条路径上累加的费用就是总的等待时间。
问题是我们怎么构图。

我们想,不让工人去找顾客,让顾客去找工人,对于同一个工人,如果他总共要给x个顾客修车,那么对于第一个顾客,就有x个人要等,没错吧。第二个顾客就有x - 1个人要等

由这样的思想,我们拆工人,拆成m * n个,每个表示倒数第i次修车的工人,让每个顾客朝他们连边,权值为i * T,i表示这是倒数第i次,要有i个人等

所有边的流量都是1,剩余边的费用为0

跑一遍费用流就出来了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 1005,maxm = 1000005,INF = 0x3f3f3f3f;

inline LL read(){
	LL out = 0,flag = 1;char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
	return out * flag;
}

LL m,n;

int head[maxn],nedge = 0;
struct EDGE{
	LL from,to,f,w,next;
}edge[maxm];

inline void build(int u,int v,LL f,LL w){
	edge[nedge] = (EDGE) {u,v,f,w,head[u]};
	head[u] = nedge++;
	edge[nedge] = (EDGE) {v,u,0,-w,head[v]};
	head[v] = nedge++;
}

LL pre[maxn],d[maxn],S,T;
bool inq[maxn];
LL cost = 0;

inline void maxflow(){
	cost = 0;
	while (true){
		fill(d,d + maxn,INF);
		d[S] = 0; pre[S] = 0;
		queue<int> q;
		q.push(S);
		int u,to;
		while (!q.empty()){
			u = q.front();
			q.pop();
			inq[u] = false;
			Redge(u) {
				if (edge[k].f && d[to = edge[k].to] > d[u] + edge[k].w){
					d[to] = d[u] + edge[k].w;
					pre[to] = k;
					if (!inq[to]){
						q.push(to);
						inq[to] = true;
					}
				}
			}
		}
		if (d[T] == INF) break;
		LL flow = INF; u = T;
		while (u != S) {flow = min(flow,edge[pre[u]].f); u = edge[pre[u]].from;}
		cost += flow * d[T];
		u = T;
		while (u != S){
			edge[pre[u]].f -= flow;
			edge[pre[u] ^ 1].f += flow;
			u = edge[pre[u]].from;
		}
	}
}

int main()
{
	fill(head,head + maxn,-1);n = read();
	m = read();
	
	S = 0;
	T = 1001;
	LL t;
	for (int i = 1; i <= m; i++){
		build(i,T,1,0);
		for (int j = 1; j <= n; j++){
			t = read();
			for (int k = 1; k <= m; k++)
				build(j * m + k,i,1,k * t);
		}
	}
	for (int i = 1; i <= n; i++)
		for (int k = 1; k <= m; k++)
			build(S,i * m + k,1,0);
	maxflow();
	printf("%.2lf\n",(double) cost / m);
	return 0;
}

posted @ 2017-11-04 13:50  Mychael  阅读(141)  评论(0编辑  收藏  举报