Description
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同
的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最
小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
Input
第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人
员维修第i辆车需要用的时间T。
Output
最小平均等待时间,答案精确到小数点后2位。
Sample Input
2 2
3 2
1 4
3 2
1 4
Sample Output
1.50
HINT
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)
/* 如果某个工人修一辆车花费t的时间,并且这是他修的倒数第k辆车,那么对答案的贡献是k*t。 我们把每个工人差拆成n个,第k各代表他修倒数第k辆车时的状态,然后建图跑费用流。 */ #include<iostream> #include<cstdio> #include<queue> #define N 1010 #define M 1000010 #define inf 1000000000 using namespace std; int t[70][70],head[N],dis[N],inq[N],fa[N],n,m,S,T,cnt=1; struct node{int v,f,w,pre;}e[M]; queue<int> q; void add(int u,int v,int f,int w){ e[++cnt].v=v;e[cnt].f=f;e[cnt].w=w;e[cnt].pre=head[u];head[u]=cnt; e[++cnt].v=u;e[cnt].f=0;e[cnt].w=-w;e[cnt].pre=head[v];head[v]=cnt; } bool spfa(){ for(int i=0;i<=T;i++) dis[i]=inf; q.push(S);dis[S]=0; while(!q.empty()){ int u=q.front();q.pop();inq[u]=0; for(int i=head[u];i;i=e[i].pre) if(e[i].f&&dis[e[i].v]>dis[u]+e[i].w){ dis[e[i].v]=dis[u]+e[i].w; fa[e[i].v]=i; if(!inq[e[i].v]){ inq[e[i].v]=1; q.push(e[i].v); } } } return dis[T]!=inf; } int updata(){ int i=fa[T],x=inf; while(i){ x=min(x,e[i].f); i=fa[e[i^1].v]; } i=fa[T]; while(i){ e[i].f-=x; e[i^1].f+=x; i=fa[e[i^1].v]; } return x*dis[T]; } int main(){ scanf("%d%d",&m,&n); S=0;T=n*m+n+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&t[i][j]); for(int i=1;i<=n*m;i++) add(S,i,1,0); for(int i=n*m+1;i<=n*m+n;i++) add(i,T,1,0); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) add((i-1)*n+j,n*m+k,1,t[k][i]*j); int ans=0; while(spfa()) ans+=updata(); printf("%.2lf",(double)ans/n); return 0; }