「BZOJ1070」[SCOI2007]修车
求平均时间最小就是求总时间最小
假设每个顾客对应的技术人员已经分配好了
那么技术人员在修某一辆车时对答案的贡献就是 time × 在排队的人数
所以可以想到把技术人员拆成n个点{mi1,mi2 ,……,min }
对于每个顾客,向mij连一条容量为1,花费为 time*j 的边
求这个二分图的最大权匹配
可以用KM算法或费用流
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1000,oo=1e9; 4 int n,m,ss,tt; 5 struct Edge{ 6 int from,to,flow,cap,cost; 7 Edge(int _from=0,int _to=0,int _flow=0,int _cap=0,int _cost=0):from(_from),to(_to),flow(_flow),cap(_cap),cost(_cost){} 8 }; 9 vector<Edge>edge; 10 int edge_tot; 11 vector<int>point[N]; 12 void add_edge(int f,int t,int c,int cc){ 13 edge.push_back(Edge(f,t,0,c,cc)); 14 point[f].push_back(edge_tot++); 15 edge.push_back(Edge(t,f,0,0,-cc)); 16 point[t].push_back(edge_tot++); 17 return; 18 } 19 int dis[N],pre[N]; 20 bool spfa(){ 21 memset(dis,127/2,sizeof(dis)); 22 queue<int>q; 23 q.push(ss); 24 dis[ss]=0; 25 int x; 26 while(!q.empty()){ 27 x=q.front();q.pop(); 28 for(int i=0;i<point[x].size();i++){ 29 Edge& e=edge[point[x][i]]; 30 if(e.cap>e.flow&&dis[e.to]>dis[x]+e.cost){ 31 dis[e.to]=dis[x]+e.cost,pre[e.to]=point[x][i]; 32 q.push(e.to); 33 } 34 } 35 } 36 return dis[tt]<oo; 37 } 38 int mincostmaxflow(){ 39 int now,minf,ans=0; 40 while(spfa()){ 41 minf=oo,now=tt; 42 while(now!=ss){ 43 minf=min(minf,edge[pre[now]].cap-edge[pre[now]].flow); 44 now=edge[pre[now]].from; 45 } 46 now=tt,ans+=minf*dis[tt]; 47 while(now!=ss){ 48 edge[pre[now]].flow+=minf,edge[pre[now]^1].flow-=minf; 49 now=edge[pre[now]].from; 50 } 51 } 52 return ans; 53 } 54 int main(){ 55 int t1; 56 scanf("%d%d",&m,&n); 57 ss=n*m+n+1,tt=ss+1; 58 for(int i=1;i<=n;i++) 59 for(int j=1;j<=m;j++){ 60 scanf("%d",&t1); 61 for(int k=0;k<n;k++) add_edge(m*n+i,k*m+j,1,t1*(k+1)); 62 } 63 for(int i=1;i<=n;i++) add_edge(ss,i+m*n,1,0); 64 for(int i=1;i<=m*n;i++) add_edge(i,tt,1,0); 65 printf("%.2lf",1.0*mincostmaxflow()/n); 66 return 0; 67 }