BZOJ 1070 修车

题意:

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

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

分析:

  (个人认为这题如果改成个第三代排队接水之类的,得有好多人拿贪心做)

  这题就是一个排队在一个水龙头接水问题的强化再强化版。

  一如既往,我们要知道一些人在维修的时候,其他人也是在等着的。

  我们用的是最暴力的建图方式,即使这样我们还是可以体会到它的巧妙。

  源点向每辆车连流量1费用0的边。

  我们把每个工人拆成n个点,每人的第i号点表示这位师傅修的第n-i+1辆车(不是他修第n-i+1辆,是他一个人所修的第n-i辆(他已经修了n-i辆了))

  之后我们将N辆车的点和这N*M个点都连起来,流量为1,费用为这位师傅的这个点的编号与他修这辆车的时间的乘积。

  表示如果让这位师傅在修过n-i辆车之后再修这辆车,为所有人带来的时间代价是多少。

  可以这样理解,如果一辆车连某个工人的第n号点,代表它是这个工人修的第一辆车,而且其他车都在这个工人排队(就是说这个工人一共要修掉n辆车)所以产生的时间代价是(n*这辆车的代价),因为一共是n个人在等。

  然后别忘了输出最小费用除以N的值。

代码:

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 const int inf=0x3f3f3f3f;
 8 const int N=100005;bool vis[N];
 9 struct node{int y,z,f,nxt;}e[N];
10 int d[N],pre[N],f[N],lst[N],h[N];
11 int n,m,c=1,ans,S,T,b[1001][1001];
12 void add(int x,int y,int f,int z){
13     e[++c]=(node){y,z,f,h[x]};h[x]=c;
14     e[++c]=(node){x,-z,0,h[y]};h[y]=c;
15 } queue<int>q;
16 bool spfa(){
17     for(int i=S;i<=T;i++)
18     vis[i]=false,pre[i]=-1,
19     lst[i]=0,d[i]=inf,f[i]=inf;
20     q.push(S);d[S]=0;vis[S]=1;pre[S]=0;
21     while(q.size()){
22         int x=q.front();q.pop();vis[x]=0;
23         for(int i=h[x],y;~i;i=e[i].nxt)
24         if(d[y=e[i].y]>d[x]+e[i].z&&e[i].f){
25             d[y]=d[x]+e[i].z;
26             pre[y]=x;lst[y]=i;
27             f[y]=min(f[x],e[i].f);
28             if(!vis[y])vis[y]=1,q.push(y);
29         }
30     } return (pre[T]!=-1);
31 } int main(){
32     scanf("%d%d",&m,&n);T=n*m+n+1;
33     for(int i=S;i<=T;i++) h[i]=-1;
34     for(int k=1;k<=n;k++)
35     add(S,m*n+k,1,0);
36     for(int k=1;k<=n;k++)
37     for(int i=1;i<=m;i++)
38     scanf("%d",&b[i][k]);
39     for(int i=1;i<=m;i++)
40     for(int j=1;j<=n;j++){
41         int x=(i-1)*n+j;
42         for(int k=1;k<=n;k++)
43         add(n*m+k,x,1,j*b[i][k]);
44         add(x,T,1,0);
45     } while(spfa()){
46         ans+=f[T]*d[T];int x=T;
47         while(x) e[lst[x]].f-=f[T],
48         e[lst[x]^1].f+=f[T],x=pre[x];
49     } printf("%.2f",ans/(n*1.0));
50 }
最小费用最大流

 

  

转载于:https://www.cnblogs.com/Alan-Luo/p/10250630.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值