题目描述
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
输入输出格式
输入格式:
第一行有两个数M,N,表示技术人员数与顾客数。
接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。
输出格式:
最小平均等待时间,答案精确到小数点后2位。
输入输出样例
输入样例#1:
2 2 3 2 1 4
输出样例#1:
1.50
说明
(2<=M<=9,1<=N<=60), (1<=T<=1000)
思路:构图+费用流
直接看了题解,这种构图,我只能说:“牛逼!”
把n个工人拆成n*m个,这样每个点就表示某个时段(并非顺次对应)的工人了,然后与n个顾客连边,边权为维修用时*工人工作时段。
然后跑一个费用流,就是总用时f(其实是每个顾客等待用时之和),然后ans=f/n。
代码实现:
1 #include<cstdio> 2 #include<cstring> 3 const int inf=2139062143; 4 const int maxn=1000; 5 const int maxm=80000; 6 int m,n,s,t,nf,nc,tc; 7 int a,b,c; 8 inline int min_(int x,int y){return x<y?x:y;} 9 int h[maxn],hs=1; 10 struct edge{int s,n,w,f;}e[maxm]; 11 void add(int q,int z,int f){ 12 e[++hs]=(edge){z,h[q],1,f},h[q]=hs; 13 e[++hs]=(edge){q,h[z],0,-f},h[z]=hs; 14 } 15 int w[maxn],p[maxn][2],q[maxm],head,tail; 16 long long la,lb; 17 int spfa(){ 18 memset(w,0x7f,sizeof(w)); 19 head=tail=0; 20 q[head++]=s,w[s]=0; 21 while(head>tail){ 22 a=q[tail++]; 23 for(int i=h[a];i;i=e[i].n) 24 if(e[i].w){ 25 la=e[i].f,lb=w[a],la+=lb,lb=w[e[i].s]; 26 if(la<lb){ 27 w[e[i].s]=la; 28 p[e[i].s][0]=i; 29 p[e[i].s][1]=a; 30 q[head++]=e[i].s; 31 } 32 } 33 } 34 return w[t]; 35 } 36 int ap(int k,int v){ 37 if(k==s) return v; 38 int ret=ap(p[k][1],min_(e[p[k][0]].w,v)); 39 e[p[k][0]].w-=ret; 40 e[p[k][0]^1].w+=ret; 41 return ret; 42 } 43 bool Dinic(){ 44 nc=spfa(); 45 if(nc==inf) return false; 46 nf=ap(t,inf); 47 tc+=nf*nc; 48 return true; 49 } 50 int main(){ 51 freopen("scoi2007_repair.in","r",stdin); 52 freopen("scoi2007_repair.out","w",stdout); 53 scanf("%d%d",&m,&n); 54 s=0,t=n*m+n+1; 55 for(int i=1;i<=n;i++) add(s,i,0); 56 for(int i=n+1;i<=n*m+n;i++) add(i,t,0); 57 for(int i=1;i<=n;i++) 58 for(int j=1;j<=m;j++){ 59 scanf("%d",&a); 60 for(int k=1;k<=n;k++) add(i,n*j+k,a*k); 61 } 62 while(Dinic()); 63 printf("%.2lf ",1.0*tc/n); 64 return 0; 65 }
aaa~反边费用忘记调成负数了。
另外,仍然建议去COGS,因为有数据。
题目来源:洛谷,COGS