【网络流】【费用流】[SCOI2007]修车

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

输入:

2 2
3 2
1 4
输出:

1.50

数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)

首先可以发现如果直接进行暴力的话那么枚举每个人的复杂度是O(M*2^N)该复杂度令人难以接受,

每个人只可以被使用一次。。。可以通过网络流来限制流量,然后如果每个人跑一次网络流。。。根本不能友好的玩耍。

但是如果每个人最多处理N辆车,那么可以处理对于每一个人来说第K辆车是当前这个人的倒数第i个处理的那么就相当于这个人第N-i+1个节点,因为是倒数第i个后面还有i-1个车等待当前工作人员处理,那么浪费的时间就是(i-1)*T+T 加一个T的原因是当前处理现在这辆车也要耗费时间

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int MAXN = 2000;
const int INF = 1e9+7;
const int MAXM = 100000;
struct node{
    int v, cost, cap;
    node *next, *back;
}Edges[MAXM*2+10], *ecnt=Edges, *adj[MAXN+10];
int dis[MAXN+10], res[MAXN+10];
node *Fa[MAXN+10];
void addedge(int u, int v, int ca, int co){
    ++ecnt;
    ecnt->v = v;
    ecnt->cap = ca;
    ecnt->cost = co;
    ecnt->next = adj[u];
    ecnt->back = ecnt+1;
    adj[u] = ecnt;

    ++ecnt;
    ecnt->v = u;
    ecnt->cap = 0;
    ecnt->cost = -co;
    ecnt->next = adj[v];
    ecnt->back = ecnt-1;
    adj[v] = ecnt;
}
int ncnt, s, t;
bool SPFA(){
    for(int i=1;i<=ncnt;i++)
        dis[i]=INF;
    dis[s] = 0;
    queue<int> que;
    que.push(s);
    res[s] = INF;
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(node *p=adj[u];p;p=p->next){
            if(p->cap == 0) continue;
            if(dis[p->v] <= dis[u] + p->cost) continue;
            dis[p->v] = dis[u] + p->cost;
            Fa[p->v] = p;
            res[p->v] = min(res[u], p->cap);
            que.push(p->v);
        }
    }
    return !(dis[t] == INF);
}
int work(){
    int ret = 0;
    while(SPFA()){
        ret += res[t] * dis[t];
        int now = t;
        while(now != s){
            Fa[now]->cap -= res[t];
            Fa[now]->back->cap += res[t];
            now = Fa[now]->back->v;
        }
    }
    return ret;
}
int n, m;
int main(){
    while(~scanf("%d%d", &m, &n)){
        memset(adj, 0, sizeof adj);
        ecnt=Edges;
        s=1, t=m*n+n+2;ncnt = m*n+n+2;
        int tmp;
        for(int i=1;i<=n;i++){
            addedge(1, i+1, 1, 0);
            for(int j=1;j<=m;j++){
                scanf("%d", &tmp);
                for(int k=1;k<=n;k++)
                    addedge(i+1, 1+n*j+k, 1, (n-k)*tmp+tmp);
            }
        }
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                addedge(1+n*i+j, t, 1, 0);
        printf("%.2lf\n", work()*1.0/n);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值