[luogu]P2053 [SCOI2007]修车

原题链接:P2053 [SCOI2007]修车

题意

有$n$辆车要修,有$m$个修理工,第$j$修理工修第$i$辆车有一个时间$r_{j,i}$。

求顾客最少的平均等待时间。

分析

由于$n$是给定的,所以最小的平均等待时间就是要求最小的总时间。

我们考虑怎么让总时间最短。

很容易发现第$i$辆车放在第$j$名修理工修,在$i$后面$j$还有还有$k$辆车要修时,$i$对总时间的贡献为$r_{j,i}*(n-p+1)$。

然后就可以用费用流解决这个问题。

我们可以把每个修理工拆成$n$个修理工,第$p$个修理工代表后面还有$n-p$辆车要修。

左边$n$个点表示车,右边$m*n$个点表示修理工,(以下所有边的容量均为1),源点向车连0边,车向修理工连$r_{j,i}*(n-p+1)$边,修理工向汇点连0边,跑最小费用最大流即可。

代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=107,M=17;
 4 const int Ma=1000009;
 5 int read(){
 6     char c;int num,f=1;
 7     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
 8     while(c=getchar(), isdigit(c))num=num*10+c-'0';
 9     return f*num;
10 }
11 queue <int> q;
12 int n,m,maxflow,ans,r[M][N],dis[Ma],vis[Ma],pre[Ma],flow[Ma];
13 int head[Ma],nxt[Ma],ver[Ma],cost[Ma],edge[Ma],tot=1,s,t;
14 void add(int u,int v,int w,int f){
15     ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;edge[tot]=w;cost[tot]=f;
16 }
17 bool spfa(){
18     while(q.size())q.pop();
19     memset(dis,0x3f,sizeof(dis));dis[s]=0;
20     memset(vis,0   ,sizeof(vis));vis[s]=1;
21     q.push(s);flow[s]=0x3f3f3f3f;
22     while(q.size()){
23         int x=q.front();
24         vis[x]=0;q.pop();
25         for(int i=head[x];i;i=nxt[i])if(edge[i]){
26             int y=ver[i];
27             if(dis[y]>dis[x]+cost[i]){
28                 dis[y]=dis[x]+cost[i];
29                 pre[y]=i;
30                 flow[y]=min(flow[x],edge[i]);
31                 if(!vis[y]){
32                     q.push(y);
33                     vis[y]=1;
34                 }
35             }
36         }
37     }
38     return dis[t]!=0x3f3f3f3f;
39 }
40 void update(){
41     int x=t;
42     while(x!=s){
43         int i=pre[x];
44         edge[i]-=flow[t];
45         edge[i^1]+=flow[t];
46         x=ver[i^1];
47     }
48     maxflow+=flow[t];
49     ans+=dis[t]*flow[t];
50 }
51 int main()
52 {
53     m=read();n=read();
54     s=0;t=(m+1)*n+1;
55     for(int i=1;i<=n;i++)
56         for(int j=1;j<=m;j++)
57             r[j][i]=read();
58     for(int i=1;i<=n;i++){
59         add(s,i,1,0);
60         add(i,s,0,0);
61     }
62     for(int j=1;j<=m;j++){
63         for(int p=1;p<=n;p++){
64             for(int i=1;i<=n;i++){
65                 add(i,j*n+p,1,r[j][i]*(n-p+1));
66                 add(j*n+p,i,0,-r[j][i]*(n-p+1));
67             }
68             add(j*n+p,t,1,0);
69             add(t,j*n+p,0,0);
70         }
71     }
72     while(spfa())update();
73     printf("%.2f
",1.0*ans/n);
74     return 0;
75 }
76 
77  
View Code
原文地址:https://www.cnblogs.com/onglublog/p/10054071.html