BZOJ 1070 修车
题意:
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
分析:
(个人认为这题如果改成个第三代排队接水之类的,得有好多人拿贪心做)
这题就是一个排队在一个水龙头接水问题的强化再强化版。
一如既往,我们要知道一些人在维修的时候,其他人也是在等着的。
我们用的是最暴力的建图方式,即使这样我们还是可以体会到它的巧妙。
源点向每辆车连流量1费用0的边。
我们把每个工人拆成n个点,每人的第i号点表示这位师傅修的第n-i+1辆车(不是他修第n-i+1辆,是他一个人所修的第n-i辆(他已经修了n-i辆了))
之后我们将N辆车的点和这N*M个点都连起来,流量为1,费用为这位师傅的这个点的编号与他修这辆车的时间的乘积。
表示如果让这位师傅在修过n-i辆车之后再修这辆车,为所有人带来的时间代价是多少。
可以这样理解,如果一辆车连某个工人的第n号点,代表它是这个工人修的第一辆车,而且其他车都在这个工人排队(就是说这个工人一共要修掉n辆车)所以产生的时间代价是(n*这辆车的代价),因为一共是n个人在等。
然后别忘了输出最小费用除以N的值。
代码:
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 const int inf=0x3f3f3f3f; 8 const int N=100005;bool vis[N]; 9 struct node{int y,z,f,nxt;}e[N]; 10 int d[N],pre[N],f[N],lst[N],h[N]; 11 int n,m,c=1,ans,S,T,b[1001][1001]; 12 void add(int x,int y,int f,int z){ 13 e[++c]=(node){y,z,f,h[x]};h[x]=c; 14 e[++c]=(node){x,-z,0,h[y]};h[y]=c; 15 } queue<int>q; 16 bool spfa(){ 17 for(int i=S;i<=T;i++) 18 vis[i]=false,pre[i]=-1, 19 lst[i]=0,d[i]=inf,f[i]=inf; 20 q.push(S);d[S]=0;vis[S]=1;pre[S]=0; 21 while(q.size()){ 22 int x=q.front();q.pop();vis[x]=0; 23 for(int i=h[x],y;~i;i=e[i].nxt) 24 if(d[y=e[i].y]>d[x]+e[i].z&&e[i].f){ 25 d[y]=d[x]+e[i].z; 26 pre[y]=x;lst[y]=i; 27 f[y]=min(f[x],e[i].f); 28 if(!vis[y])vis[y]=1,q.push(y); 29 } 30 } return (pre[T]!=-1); 31 } int main(){ 32 scanf("%d%d",&m,&n);T=n*m+n+1; 33 for(int i=S;i<=T;i++) h[i]=-1; 34 for(int k=1;k<=n;k++) 35 add(S,m*n+k,1,0); 36 for(int k=1;k<=n;k++) 37 for(int i=1;i<=m;i++) 38 scanf("%d",&b[i][k]); 39 for(int i=1;i<=m;i++) 40 for(int j=1;j<=n;j++){ 41 int x=(i-1)*n+j; 42 for(int k=1;k<=n;k++) 43 add(n*m+k,x,1,j*b[i][k]); 44 add(x,T,1,0); 45 } while(spfa()){ 46 ans+=f[T]*d[T];int x=T; 47 while(x) e[lst[x]].f-=f[T], 48 e[lst[x]^1].f+=f[T],x=pre[x]; 49 } printf("%.2f",ans/(n*1.0)); 50 }