bzoj1070: [SCOI2007]修车 网络流

bzoj1070: [SCOI2007]修车

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)

分析

数据小就是可以为所欲为的
匹配应该是网络流费用流的,顺序不确定就枚举呗。
具体地就是拆点,把工人拆成 n m 个点代表顺序。
可是会发现我们无法统计这个车主之前等待的时间。
一个很巧妙的方法是换成倒着修。
具体地,就是每个工人的第 k 个点表示这个工人倒数第k个修某辆车。
这样的话每个车主对之后车主造的孽的影响是很好统计的,假设是第 k 个,影响就是 k T
每个点和所有车主连一遍边,容量是1,费用是 k T ,跑网络流就好了。

代码

#include<cstdio>
#include<algorithm>
const int N = 1e3 + 10, M = 1e6 + 10, inf = 2e9;
int D[N], nx[M], to[M], pr[N], Pr[N], q[N], f[M], w[M], t[100][100], tp = 1, T, S, cost, n, m; bool v[N];
void ins(int u, int v, int W, int F) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp; f[tp] = F; w[tp] = W;}
void add(int u, int v, int w, int f) {ins(u, v, w, f); ins(v, u, 0, -f);}
int Nx(int &x) {return x = (x == T + 2 ? 0 : x + 1);}
bool Spfa() {
    for(int i = 1;i <= T; ++i) D[i] = inf;
    int L = 0, R; q[R = 1] = S; D[S] = 0; v[S] = true;
    for(;L != R;) {
        int u = q[Nx(L)]; v[u] = false;
        for(int i = pr[u]; i; i = nx[i])
            if(w[i] && D[to[i]] > D[u] + f[i])
                D[to[i]] = D[u] + f[i], Pr[to[i]] = i, (!v[to[i]] ? v[q[Nx(R)] = to[i]] = true : 0);
    }
    return D[T] != inf;
}
void Aug() {
    int fw = inf;
    for(int i = T; i != S; i = to[Pr[i] ^ 1]) fw = std::min(fw, w[Pr[i]]);
    for(int i = T; i != S; i = to[Pr[i] ^ 1]) w[Pr[i]] -= fw, w[Pr[i] ^ 1] += fw;
    cost += D[T] * fw;
}
void MCMF() {while(Spfa()) Aug();}
int main() {
    scanf("%d%d", &m, &n);
    for(int i = 1;i <= n; ++i)
        for(int j = 1;j <= m; ++j)
            scanf("%d", &t[i][j]);
    S = n * m + n + 1; T = S + 1;
    for(int i = 1;i <= n * m; ++i) add(S, i, 1, 0);
    for(int i = n * m + 1; i <= n * m + n; ++i)  add(i, T, 1, 0);
    for(int i = 1;i <= m; ++i)
        for(int j = 1;j <= n; ++j)
            for(int k = 1; k <= n; ++k)
                add((i - 1) * n + j, k + n * m, 1, j * t[k][i]);
    MCMF(); printf("%.2lf\n", (double)cost / (double)n);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/81415310
今日推荐