• 【BZOJ1070】[SCOI2007]修车


    【BZOJ1070】[SCOI2007]修车

    题面

    以后要多写题面flag

    题目描述

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

    说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

    输入格式

    第一行有两个数(M,N),表示技术人员数与顾客数。

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

    输出格式

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

    样例

    输入样例

    2 2
    3 2
    1 4
    

    输出样例

    1.50
    

    说明

    ((2leq Mleq 9,1leq Nleq 60), (1leq Tleq 1000))

    题解

    设某个技术人员的修车序列为(a_1,a_2...a_n)

    则这个人所用时间

    [sum_{i=1}^nT_{a_i}*(n-i+1)\ Leftrightarrow n*T_{a_1}+(n-1)*T_{a_2}+...+1*T_{a_n} ]

    这样的话,我们可以将一次在第(k)次修决策化为一次

    费用为(T_{i,j}*k)的决策

    因此我们可以得到一个决策集合:决策(left(i,j,k ight)=Tleft(i,j ight)ast k)表示“把第i辆车让第j个人在“需要消耗k次时间”的那个个位置修”

    那实际上我们就是对于每个(i)选取一个这样的决策,同时这个决策的(left(j,k ight))不能相同

    最后怎么办呢?

    建一个(n*m)的决策图,表示决策(j,k)

    再建(n)个车的点,表示那辆车

    再对于决策图的每一层,向车(i)(Ti,j*层数)费用,容量为(1)的边

    最后连(S,T)即可

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <queue> 
    using namespace std; 
    const int MAX_N = 300; 
    const int INF = 1e9; 
    struct Graph { int to, cap, cost, next; } e[MAX_N * MAX_N << 2]; 
    int fir[MAX_N * MAX_N], e_cnt, V; 
    void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
    void Add_Edge(int u, int v, int cap, int cost) { 
        e[e_cnt] = (Graph){v, cap, cost, fir[u]}; fir[u] = e_cnt++; 
        e[e_cnt] = (Graph){u, 0, -cost, fir[v]}; fir[v] = e_cnt++; 
    }
    int dis[MAX_N * MAX_N], preve[MAX_N * MAX_N], prevv[MAX_N * MAX_N]; 
    bool inq[MAX_N * MAX_N]; 
    int min_cost_flow(int s, int t) { 
        static queue<int> que; int res = 0; 
        while (1) { 
            fill(&dis[0], &dis[V + 1], INF); 
            fill(&inq[0], &inq[V + 1], 0); 
            que.push(s), dis[s] = 0, inq[s] = 1; 
            while (!que.empty()) { 
                int x = que.front(); que.pop(); 
                for (int i = fir[x]; ~i; i = e[i].next) { 
                    int v = e[i].to; 
                    if (dis[x] + e[i].cost < dis[v] && e[i].cap > 0) { 
                        dis[v] = dis[x] + e[i].cost; 
                        preve[v] = i, prevv[v] = x; 
                        if (!inq[v]) que.push(v), inq[v] = 1; 
                    } 
                }
                inq[x] = 0; 
            } 
            if (dis[t] == INF) return res; 
            int d = INF; 
            for (int x = t; x != s; x = prevv[x]) d = min(d, e[preve[x]].cap); 
            res += dis[t] * d; 
            for (int x = t; x != s; x = prevv[x]) { 
                e[preve[x]].cap -= d; 
                e[preve[x] ^ 1].cap += d; 
            } 
        } 
    }
    int N, M, id[MAX_N][MAX_N], T[MAX_N][MAX_N]; 
    int main () {
        clearGraph(); 
        cin >> M >> N; int s = 0, t, tot = 0; 
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++) id[i][j] = ++tot; 
        for (int i = 1; i <= N; i++) 
            for (int j = 1; j <= M; j++) cin >> T[i][j]; 
        V = t = (N + 1) * M + 1; 
        for (int i = 1; i <= N; i++) Add_Edge(s, i, 1, 0);
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++) Add_Edge(N + id[i][j], t, 1, 0); 
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
                for (int k = 1; k <= N; k++) 
                    Add_Edge(i, N + id[k][j], 1, T[i][j] * k); 	
        printf("%0.2lf
    ", 1.0 * min_cost_flow(s, t) / N); 
        return 0; 
    } 
    
  • 相关阅读:
    Elasticsearch--预匹配器
    Elasticsearch--建议器
    Elasticsearch--聚合
    Elasticsearch--扩展索引结构
    Elasticsearch--更好的搜索_加权得分,脚本,同义词
    Elasticsearch--搜索
    信息论基础概念
    一个人的思想决定一个人的行为,一个人的行为决定一个人的习惯,一个人的习惯决定一个人的性格,一个人的性格决定一个人的命运,一个人的命运决定一个人的一生。
    宝塔的外网地址忘记 解决办法
    一定要先看文档 hyperf
  • 原文地址:https://www.cnblogs.com/heyujun/p/10289861.html
Copyright © 2020-2023  润新知