题目链接
题目描述
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
Sample Output
1.50
HINT
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)
题解
这题每个顾客的等待时间也要计算,这便是麻烦之处。
考虑第i个人修第j辆车,如果这辆车是倒数第k台被修理的,那么k辆车都有等待t的时间,相当于费用为t[j,i]* k。那么我们把m个人拆成n*m个点,每个人的第i个点代表他修理的车是倒数第i辆,将这个点分别向n辆车连边,费用为i *t。跑一遍费用流就行了。其实就相当于将所有情况的费用提前计算出来。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
#define N 605
struct edge{
int x,next,cost,data,f;
}e[100000];
int first[N],c[N*N],v[N],dis[N],ti[N][N],pre[N],tot=1,n,m,p,q,s,t;
void add(int x,int y,int d,int c){
e[++tot].x=y;
e[tot].data=d;
e[tot].cost=c;
e[tot].f=x;
e[tot].next=first[x];
first[x]=tot;
if(~tot&1) add(y,x,0,-c);
}
bool spfa(){
memset(dis,63,sizeof(dis));
memset(v,0,sizeof(v));
v[c[1]=s]=1; dis[s]=0;
for(p=q=1;p<=q;v[c[p]]=0,p++)
for(int i=first[c[p]];i;i=e[i].next)
if(e[i].data&&dis[e[i].x]>dis[c[p]]+e[i].cost){
dis[e[i].x]=dis[c[p]]+e[i].cost;
pre[e[i].x]=i;
if(!v[e[i].x]) v[c[++q]=e[i].x]=1;
}
return dis[t]!=dis[0];
}
int cost_flow(){
int ans=0,flow;
while(spfa()){
flow=1000000007;
for(int i=pre[t];i;i=pre[e[i].f]) flow=min(flow,e[i].data);
ans+=flow*dis[t];
for(int i=pre[t];i;i=pre[e[i].f]) e[i].data-=flow,e[i^1].data+=flow;
}
return ans;
}
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) scanf("%d",&ti[i][j]);
s=n*m+n+1; t=n*m+n+2;
for(int i=1;i<=n*m;i++) add(s,i,1,0);
for(int i=1;i<=n;i++) add(i+n*m,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+k,n*m+j,1,ti[j][i]*k);
printf("%.2f",(double)cost_flow()/n);
return 0;
}