1. 程式人生 > >[luogu]P2053 [SCOI2007]修車

[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\n",1.0*ans/n); 74 return 0; 75 } 76 77
View Code