洛谷 P2053 :[SCOI2007]修车(拆点+最小费用流)

https://www.luogu.org/problem/P2053

题目描述

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

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

输入格式

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

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

输出格式

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

输入输出样例

输入 #1

2 2

3 2

1 4

输出 #1

1.50

说明/提示

(2<=M<=9,1<=N<=60), (1<=T<=1000)

解题思路:

把每个工作人员拆分为n个,代表每个阶段的工人,这样一共有n*m个,源点和车费0流1, 每个阶段的工人和汇点费0流1,每个车与第i个阶段的工人的费用为 i*cost,代表如果这个工人后面有i-1个需要修理的车,需要等待的时间,求出最小费用流。

#include <stdio.h>
#include <string.h>
#include <vector>
#define N 1020
using namespace std;
struct edge{
    int v;
    int w;
    int cost;
    int rev;
};
vector<edge>e[N];
int n, m, prevv[N], preve[N], dis[N], inf=0x3f3f3f3f;

int add(int u, int v, int w, int cost)
{
    e[u].push_back(edge{v, w, cost, e[v].size()});
    e[v].push_back(edge{u, 0, -cost, e[u].size()-1});
}
int min_cost(int s, int t)
{
    int ans=0;
    while(1)
    {
        for(int i=0; i<=t; i++)
            dis[i]=inf;
        dis[s]=0;
        bool update=true;
        while(update)
        {
            update=false;
            for(int v=0; v<=t; v++)
            {
                if(dis[v]==inf)
                    continue;
                for(int i=0; i<e[v].size(); i++)
                {
                    edge &G=e[v][i];
                    if(G.w && dis[G.v]>dis[v]+G.cost)
                    {
                        dis[G.v]=dis[v]+G.cost;
                        prevv[G.v]=v;
                        preve[G.v]=i;
                        update=true;
                    }
                }
            }
        }
        if(dis[t]==inf)
            return ans;
        int d=1;
//		for(int v=t; v!=s; v=prevv[v])
//		{
//			d=min(d, e[prevv[v]][preve[v]].w);
//		}
        ans+=d*dis[t];
        for(int v=t; v!=s; v=prevv[v])
        {
            edge &G = e[prevv[v]][preve[v]];
            G.w-=d;
            e[v][G.rev].w+=d;
        }
    }
    return ans;
}
int main()
{
    int w;
    while(scanf("%d%d", &m, &n)!=EOF)
    {
        int s=0, t=n*(m+1)+1; 
        for(int i=1; i<=t; i++)
            e[i].clear();
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
            {
                scanf("%d", &w);
                for(int k=1; k<=n; k++)
                    add(i, j*n+k, 1, w * k);
            }
        for(int i=1; i<=n; i++)
            add(s, i, 1, 0);
        for(int i=n+1; i<t; i++)
            add(i, t, 1, 0);
        printf("%.2lf\n", 1.0*min_cost(s, t)/n);
    }
    return 0;
} 

 

posted @ 2019-08-12 11:03  宿星  阅读(130)  评论(0编辑  收藏  举报