BZOJ1070[SCOI2007]修车——最小费用最大流

题目描述

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

输入

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

输出

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

 
从题意可以明显看出这是一道最小费用最大流,但显然不能直接把工人建在一边,汽车建在另一边,因为一个工人可能修多辆车,在修前面车的时候,后面车就要有等待时间。因此可以把每个工人拆开成n个工人,表示n个时间段。将这n辆汽车和n*m个工人连边,形成一个完全二分图。因为每辆修的车只会影响后面车的等待时间,所以对于每条边表示第i辆汽车,被第j个工人(题目中的工人,不是拆开的)在倒数第k个时间段(也就是说这辆车是这个工人倒数第k个修的车)修所耗费的时间是k*v[i][j](因为是倒数第k个,所以包括他在内的后面k个车都要等待v[i][j]的时间)。这样再跑最小费用最大流就可以求出最小时间了。
最后附上代码。
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
queue<int>q;
int d[1003];
int f[1003];
int v[100010];
int c[100010];
int vis[1003];
int to[100010];
int head[100010];
int next[100010];
int from[100010];
int n,m;
int S,T;
int x;
int tot=1;
int ans=0;
int INF=1<<30;
int maxflow=0;
void add(int x,int y,int z,int w)
{
    tot++;
    next[tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    c[tot]=z;
    v[tot]=w;
    from[tot]=x;
    tot++;
    next[tot]=head[y];
    head[y]=tot;
    to[tot]=x;
    c[tot]=0;
    v[tot]=-w;
    from[tot]=y;
}
void result()
{
    int now=T;
    int flow=INF;
    while(now!=S)
    {
        flow=min(flow,c[f[now]]);
        now=from[f[now]];
    }
    maxflow+=flow;
    ans+=d[T]*flow;
    now=T;
    while(now!=S)
    {
        c[f[now]]-=flow;
        c[f[now]^1]+=flow;
        now=from[f[now]];
    }
}
bool SPFA()
{
    for(int i=1;i<=T;i++)
    {
        d[i]=INF;
    }
    d[S]=0;
    q.push(S);
    vis[S]=1;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        vis[now]=0;
        for(int i=head[now];i;i=next[i])
        {
            if(!c[i])
            {
                continue;
            }
            if(d[to[i]]>d[now]+v[i])
            {
                d[to[i]]=d[now]+v[i];
                f[to[i]]=i;
                if(!vis[to[i]])
                {
                    q.push(to[i]);
                    vis[to[i]]=1;
                }
            }
        }
    }
    return d[T]!=INF;
}
void find_min()
{
    while(SPFA())
    {
        result();
    }
}
int main()
{
    scanf("%d%d",&m,&n);
    S=n*m+n+16;
    T=n*m+n+28;
    for(int i=1;i<=n;i++)
    {
        add(S,n*m+i,1,0);
    }
    for(int i=1;i<=n*m;i++)
    {
        add(i,T,1,0);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            for(int k=1;k<=n;k++)
            {
                add(n*m+i,(j-1)*n+k,1,k*x);
            }
        }
    }
    find_min();
    printf("%.2lf",((double)ans)/((double)n));
    return 0;
}
原文地址:https://www.cnblogs.com/Khada-Jhin/p/9123418.html