bzoj1070 [SCOI2007]修车

1070: [SCOI2007]修车

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 6643  Solved: 2870
[Submit][Status][Discuss]

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)

分析:这道题和bzoj1449很像.

   先来看看它们有什么相似之处.

   1.最后的答案是每一部分的贡献之和.

   2.每一部分的贡献是不确定的,有单调性.

   3.要用费用流解决.(求最值,有数量限制)

   解决这类问题的方法就是拆边!

   这道题中修一辆车的贡献就是让它之后的车主等待的时间和. 如果只有一位修车工,当前的车是第i辆被修的,那么它的贡献就是(n - i + 1) * 所花的时间.  建图跑费用流,可以A掉.

   这种解法是有问题的,A掉只是碰巧罢了.修车的费用随着i的增加是递减的,最小费用流肯定先跑费用最小的那条边. 那么第1辆车就会被最后给修理. 在只有一个修车工的时候是可以的,但是多个修车工就不行了.  因为第一个修车工可能不会修n辆车,他可能只会修n-1辆车,而之前的方案却安排第一辆车是他修的第n辆车,这显然是不合法的.

   所以问题有两个:1.每个人修多少辆车不知道.2.费用是递减的,就算确定了修多少辆车可能还是不合法.

   怎么办呢?换个定义就好了......

   令当前的车是倒数第i辆被修的,那么它的贡献就是i*所花的时间. 贡献递增. 而且注意关键词:倒数. 说明在它之间的车都已经被修了,不会出现不合法的情况.有那么一点哲学的意味......

   最奇葩的是,两种方法都能A掉,无力吐槽.

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;
const int inf = 1000000000;

int n, m, to[100000], nextt[100000], head[100000], tot, w[100000], cost[100000], vis[100000], d[100000], p[100000], s, t;

void add(int x, int y, int c, int h)
{
    to[tot] = y;
    w[tot] = c;
    cost[tot] = h;
    nextt[tot] = head[x];
    head[x] = tot++;
}

bool spfa()
{
    memset(vis, 0, sizeof(vis));
    memset(d, 0x3f, sizeof(d));
    memset(p, -1, sizeof(p));
    d[s] = 0;
    queue <int> q;
    q.push(s);
    vis[s] = 1;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u];i != -1; i = nextt[i])
        {
            if (w[i])
            {
                int v = to[i];
                if (d[u] + cost[i] < d[v])
                {
                    d[v] = cost[i] + d[u];
                    p[v] = i;
                    if (!vis[v])
                    {
                        q.push(v);
                        vis[v] = 1;
                    }
                }
            }
        }
    }
    if (p[t] != -1)
        return true;
    return false;
}

int solve_min()
{
    int res = 0;
    int f = 0;
    while (spfa())
    {
        int flow = inf;
        for (int i = t;i != s; i = to[p[i] ^ 1])
            flow = min(w[p[i]], flow);
        for (int i = t; i != s; i = to[p[i] ^ 1])
        {
            w[p[i]] -= flow;
            w[p[i] ^ 1] += flow;
            res += flow * cost[p[i]];
        }
        f += flow;
    }
    return res;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &m, &n);
    s = 0, t = n * m + n + 1;
    for (int i = 1; i <= n; ++i) {
        add(i + m * n, t, 1, 0);
        add(t, i + m * n, 0, 0);
    }
    for (int j = 1; j <= m; ++j) {
        for (int k = 1; k <= n; ++k) {
            add(s, (j - 1) * n + k, 1, 0);
            add((j - 1) * n + k, s, 0, 0);
        }
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            int t;
            scanf("%d", &t);
            for (int k = 1; k <= n; k++)
            {
                add((j - 1) * n + k, i + m * n, 1, t * k);
                add(i + m * n, (j - 1) * n + k, 0, -t * k);

            }
        }
    int ans = solve_min();
    printf("%.2lf", 1.0 * ans / n);

    return 0;
}

 

posted @ 2018-03-18 16:23  zbtrs  阅读(221)  评论(0编辑  收藏  举报