zoukankan      html  css  js  c++  java
  • 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;
    }

     

  • 相关阅读:
    PowerDesigner最基础的使用方法入门学习
    使用vertx共享数据
    VMware中虚拟机与主机不能ping通解决办法
    Win10系统的SurfacePro4无法修改启动顺序怎么办
    Win10系统的SurfacePro4如何重装系统-4 如何再次备份和还原系统
    Win10系统的SurfacePro4的启动菜单太多怎么管理,UEFI的启动菜单如何编辑
    Win10系统的SurfacePro4如何重装系统-3 重装完成之后的系统优化
    Win10系统的SurfacePro4如何重装系统-2 重装WIN10系统
    Win10系统的SurfacePro4如何重装系统-1 SurfacePro专用的PE
    Win10系统的DELL平板如何重装WIN10系统
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8595950.html
Copyright © 2011-2022 走看看