题目描述
同一时刻有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)
思路
对于每一位师傅,都有ki个车等待修理,那么第i辆车修理的时间对答案的贡献应该为(ki-i+1)*ti,如果倒推,则为倒数第i辆车的贡献为i*ti,可以直接计入答案。所以对于所有的车,在每一位师傅上分别有n*m种情况,因此我们可以对每个师傅的每个时刻和每一辆车进行建边,最后跑最大流最小费用进行求解。
代码
#include<bits/stdc++.h> #define N 10700 #define M 107000 #define inf 1<<29 using namespace std; struct node{ int y,z,p,next; }e[M*2]; int tot=1,head[N],maxflow=0,ans=0; int n,m,s,t; void add(int x,int y,int z,int p){ e[++tot].y=y;e[tot].z=z;e[tot].p=p; e[tot].next=head[x];head[x]=tot; } int incf[N],v[N],pre[N],d[N]; bool spfa(){ queue<int> q; memset(d,0x3f,sizeof(d));// 0xcf memset(v,0,sizeof(v)); q.push(s);d[s]=0;v[s]=1; incf[s]=inf; while(q.size()){ int x=q.front();v[x]=0;q.pop(); for(int i=head[x];i;i=e[i].next){ int y=e[i].y,z=e[i].z; if(!z) continue; if(d[y]>d[x]+e[i].p){//d[y]<d[x]+e[i].p d[y]=d[x]+e[i].p; incf[y]=min(incf[x],z); pre[y]=i; if(!v[y]) v[y]=1,q.push(y); } } } if(d[t]==0x3f3f3f3f) return false;//0xcfcfcfcf return true; } void update(){ int x=t; while(x!=s){ int i=pre[x]; e[i].z-=incf[t]; e[i^1].z+=incf[t]; x=e[i^1].y; } maxflow+=incf[t]; ans+=d[t]*incf[t]; } int main() { scanf("%d%d",&m,&n);s=n+n*m+1,t=n+n*m+2; for(int i=1;i<=n;i++)add(s,i,1,0),add(i,s,0,0); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int c;scanf("%d",&c); for(int k=1;k<=n;k++){ add(i,j*n+k,1,c*k); add(j*n+k,i,0,-1*c*k); } } } for(int i=1;i<=n*m;i++){ add(n+i,t,1,0);add(t,n+i,0,0); } while(spfa()) update(); printf("%.2lf",(double)ans/n); return 0; }