zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Unity3d中的属性(Attributes)整理【转载】
    在Unity里面使MMD动起来吧【2】
    在Unity里面使MMD动起来吧【1】
    Unity代码混淆方案
    萌舞Android版Unity笔记整理
    c#实现16进制和字符串之间转换的代码
    关于sqlite3使用top的一些规则总结
    【转】UniSky入门资料
    【转】.NET 产品版权保护方案 (.NET源码加密保护)
    百度云管家下载出错解决思路记录
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9123418.html
Copyright © 2011-2022 走看看