[省选前题目整理][BZOJ 1070][SCOI 2011]修车(费用流)

142 篇文章 0 订阅
98 篇文章 0 订阅

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1070

思路

有意思的是这道题在后来某年NOI出现过,不过加强了数据,可见此题有多么经典。

比较显然的思路就是先求出n个顾客总的等待时间,再求出平均等待时间。可以发现,对于每个工人而言,他修完1辆车所耗费的时间,只会对他之后修的每一辆车的主人的等待时间产生影响,这个影响就是修当前这辆车的耗费时间,也就是说,假如这个工人修当前这辆车耗费了时间T,之后还要修k-1辆车,会使n个顾客总的等待时间加上k*T。我们可以将n个汽车看成n个点,将m个工人中每个人的状态拆成n个,用Node i,j来表示第i个工人的第j个状态,表示第i个工人修完当前的车后还要修j-1辆车,共m*n个点。源向每辆车连容量为1,费用为0的边,限制整个图的最大流不超过n。每辆车向Node i,j连容量为1,费用为第i个人修第j辆车的时间*j,对于每个Node i,j,向汇连容量为1,费用为0的边,表示每个工人的修车过程随时可以结束掉。显然整个图的最大流就是n,我们在保证最大流的前提下(保证每辆车都被修),求出最小费用(最小的总的等待时间),因此用最小费用最大流便可以解决此题。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXE 500000
#define MAXV 1000
#define INF 0x3f3f3f3f

using namespace std;

int S,T;

struct edge
{
    int u,v,w,cap,next;
}edges[MAXE];

int head[MAXV],nCount=1;

void AddEdge(int U,int V,int W,int C)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].w=W;
    edges[nCount].cap=C;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

void add(int U,int V,int W,int C)
{
    AddEdge(U,V,W,C);
    AddEdge(V,U,-W,0);
}

int q[2*MAXE],dist[MAXV],pre[MAXV];
bool inQueue[MAXV];

bool SPFA()
{
    memset(pre,-1,sizeof(pre));
    memset(dist,INF,sizeof(dist));
    memset(inQueue,false,sizeof(inQueue));
    int h=0,t=1;
    q[h]=S;
    dist[S]=0;
    inQueue[S]=true;
    while(h<t)
    {
        int u=q[h++];
        inQueue[u]=false;
        for(int p=head[u];p!=-1;p=edges[p].next)
        {
            int v=edges[p].v;
            if(dist[u]+edges[p].w<dist[v]&&edges[p].cap)
            {
                dist[v]=dist[u]+edges[p].w;
                pre[v]=p;
                if(!inQueue[v])
                {
                    inQueue[v]=true;
                    q[t++]=v;
                }
            }
        }
    }
    return pre[T]!=-1;
}

int MCMF()
{
    int cost=0;
    while(SPFA())
    {
        int flow=INF;
        for(int p=pre[T];p!=-1;p=pre[edges[p].u])
            flow=min(flow,edges[p].cap); //!!!
        for(int p=pre[T];p!=-1;p=pre[edges[p].u])
        {
            edges[p].cap-=flow;
            edges[p^1].cap+=flow;
        }
        cost+=flow*dist[T];
    }
    return cost;
}

int spendtime[MAXV][MAXV];

int main()
{
    memset(head,-1,sizeof(head));
    int n,m;
    scanf("%d%d",&m,&n); //m个人,n辆车
    S=MAXV-2,T=MAXV-1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&spendtime[i][j]);
    for(int i=1;i<=n;i++) //枚举第i辆车
    {
        add(S,i,0,1);
        for(int j=1;j<=m;j++) //枚举第j个人修第i辆车
            for(int k=1;k<=n;k++) //枚举第j个人修第i辆车之后还要修k-1辆车
                add(i,j*n+k,k*spendtime[i][j],1);
    }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            add(i*n+j,T,0,1);
    printf("%.2lf\n",(double)MCMF()/n);
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值