BZOJ1070 / SCOI2007 修车【网络流/费用流】

来源:互联网 发布:软件项目团队介绍 编辑:程序博客网 时间:2024/05/20 02:53

Description

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

Input

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

Output

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

Solution

我们可以发现每位顾客修车花费的时间只会对他后面修车的人的等待时间造成影响。那么修车工i修倒数第j辆车k造成的花费是t[j][i]×k

这样的话可以费用流。这是一个二分图,因为同一个时间同一个修车工只可以修一辆车,所以把每个修车工的每个时间(倒数第几个修车)拆开成很多点,每个点连向一辆车有一定的费用(即修他的费用)。

考虑原点?因为同一个时间同一个修车工只可以修一辆车,那么从S到修车工连容量为1边,费用0
考虑汇点?因为每个车只需要修一次,所以从每辆车到T连容量为1的边,费用0

Code

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int maxn = 50000 + 5;const int INF = 1e9;int edge_num = 1, m, n, S, T, ans = 0, mincost = 0;int hed[maxn], ct[maxn];int t[61][10];struct Edge {    int from, to, nxt, c, cost;} edge[maxn * 4];void addedge(int from, int to, int c, int cost){    edge[++edge_num].nxt = hed[from];    edge[edge_num].from = from;    edge[edge_num].to = to;    hed[from] = edge_num;    edge[edge_num].c = c;    edge[edge_num].cost = cost;}void adde(int from, int to, int c, int cost){    addedge(from, to, c, cost);    addedge(to, from, 0, -cost);}queue<int> q;int inq[maxn], prev[maxn] = {-1}, pree[maxn];bool SPFA(){    memset(ct, 0x3f3f, sizeof(ct));    inq[S] = 1;    ct[S] = 0;    q.push(S);    while (!q.empty()){        int cur = q.front();        q.pop();        for (int i = hed[cur]; i; i = edge[i].nxt){            int to = edge[i].to;            if (ct[to] > ct[cur] + edge[i].cost && edge[i].c){                if (!inq[to]){                    inq[to] = 1;                    q.push(to);                }                ct[to] = ct[cur] + edge[i].cost;                prev[to] = cur;    pree[to] = i;            }        }        inq[cur] = 0;    }    if (ct[T] == ct[maxn - 1]) return 0;    int flow = INF;    for (int cur = T; ~prev[cur]; cur = prev[cur]){        int ed = pree[cur];        flow = min(flow, edge[ed].c);    }    for (int cur = T; ~prev[cur]; cur = prev[cur]){        int ed = pree[cur];        edge[ed].c -= flow;        edge[ed ^ 1].c += flow;    }    ans += flow;    mincost += flow * ct[T];    return 1;}void MinCostMaxFlow(){    while (SPFA());}int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= m; i++)        for (int j = 1; j <= n; j++)            scanf("%d", &t[i][j]);    S = 0, T = 1001;    for(int i = 1; i <= n * m; i++)        adde(S, i, 1, 0);    for(int i = n * m + 1; i <= n * m + m; i++)        adde(i, T, 1, 0);    for(int i = 1; i <= n; i++)        for(int j = 1; j <= m; j++)            for(int k = 1; k <= m; k++)                adde((i - 1) * m + j, n * m + k, 1, t[k][i] * j);    MinCostMaxFlow();    printf("%.2f\n", (double)mincost / m);    return 0;}
原创粉丝点击