「BZOJ1070」[SCOI2007] 修车
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)
题解
没写cnt=1调了半天、、、
N辆车,M个工人。
把每个工人拆成N个点。记为A[i,j]表示第i个工人修倒数第j辆车。
每个车跟所有N*M个工人拆出的点连边。流量为1,费用为time[i,j]*k。
源和每辆车连边,N*M个点和汇连边,流量都为1,费用同为0。
为什么这么构图呢?
考虑第i个工人,他修第j辆车只对后面要修的车有影响,而前面修过的车已经对当前没有影响了。
而这个影响就是后面每个将要修理的车都多等待了time的时间。
其他边流量都为1是显然的,每辆车修一次,每个工人一个时段只能修理一辆车。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include<iostream> #include<cstdio> #include<cstring> #define inf 0x7fffffff #define T 1001 using namespace std; int n,m,cnt=1,ans,t[61][10]; int d[1005],q[1005],from[1005],head[1005]; bool inq[1005]; struct edge{int from,to,next,c,v;}e[100001]; void ins(int u,int v,int w,int c) { cnt++; e[cnt].from=u;e[cnt].to=v; e[cnt].next=head[u];head[u]=cnt; e[cnt].c=c;e[cnt].v=w; } void insert(int u,int v,int w,int c) {ins(u,v,w,c);ins(v,u,0,-c);} bool spfa() { for(int i=0;i<=T;i++)d[i]=inf; int t=0,w=1;d[0]=0;inq[0]=1;q[0]=0; while(t!=w) { int now=q[t];t++;if(t==T)t=0; for(int i=head[now];i;i=e[i].next) if(e[i].v&&d[e[i].to]>d[now]+e[i].c) { d[e[i].to]=d[now]+e[i].c;from[e[i].to]=i; if(!inq[e[i].to]) {inq[e[i].to]=1;q[w++]=e[i].to;if(w==T)w=0;} } inq[now]=0; } if(d[T]==inf)return 0; return 1; } void mcf() { int x=inf; for(int i=from[T];i;i=from[e[i].from]) x=min(x,e[i].v); for(int i=from[T];i;i=from[e[i].from]) {e[i].v-=x;e[i^1].v+=x;ans+=e[i].c*x;} } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&t[i][j]); for(int i=1;i<=n*m;i++) insert(0,i,1,0); for(int i=n*m+1;i<=n*m+m;i++) insert(i,T,1,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++) insert((i-1)*m+j,n*m+k,1,t[k][i]*j); while(spfa())mcf(); printf("%.2lf",(double)ans/m); return 0; } |
zkw快一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#include<iostream> #include<cstdio> #include<cstring> #define inf 0x7fffffff #define T 601 using namespace std; int n,m,cnt=1,ans,t[61][10]; int d[605],q[605],from[605],head[605]; bool mark[605]; struct edge{int from,to,next,c,v;}e[100001]; void ins(int u,int v,int w,int c) { cnt++; e[cnt].from=u;e[cnt].to=v; e[cnt].next=head[u];head[u]=cnt; e[cnt].c=c;e[cnt].v=w; } void insert(int u,int v,int w,int c) {ins(u,v,w,c);ins(v,u,0,-c);} bool spfa() { memset(mark,0,sizeof(mark)); for(int i=0;i<=T;i++)d[i]=inf; int t=0,w=1; d[T]=0;mark[T]=1;q[0]=T; while(t!=w) { int now=q[t];t++;if(t==T)t=0; for(int i=head[now];i;i=e[i].next) if(e[i^1].v&&d[e[i].to]>d[now]-e[i].c) { d[e[i].to]=d[now]-e[i].c; if(!mark[e[i].to]) {mark[e[i].to]=1;q[w++]=e[i].to;if(w==T)w=0;} } mark[now]=0; } if(d[0]==inf)return 0; return 1; } int dfs(int x,int f) { if(x==T){mark[T]=1;return f;} int used=0,w; mark[x]=1; for(int i=head[x];i;i=e[i].next) if(!mark[e[i].to]&&e[i].v&&d[x]-e[i].c==d[e[i].to]) { w=f-used; w=dfs(e[i].to,min(e[i].v,w)); ans+=w*e[i].c; e[i].v-=w;e[i^1].v+=w; used+=w;if(used==f)return f; } return used; } void zkw() { while(spfa()) { mark[T]=1; while(mark[T]) { memset(mark,0,sizeof(mark)); dfs(0,inf); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&t[i][j]); for(int i=1;i<=n*m;i++) insert(0,i,1,0); for(int i=n*m+1;i<=n*m+m;i++) insert(i,T,1,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++) insert((i-1)*m+j,n*m+k,1,t[k][i]*j); zkw(); printf("%.2lf",(double)ans/m); return 0; } |
啊……黄学长我有个问题啊……
这个zkw费用流和普通费用流为什么看上去没啥区别啊……
就是每次spfa算多条增广路吗…可是到T距离又不修改的话,不是只有几条最短路径不相交的时候才有优化吗……感觉和网上的zkw费用流完全不是一个风格(不过还是看不懂orz
不过,讲道理的话距离真的不用修改吗……这样不会降低效率吗qwq
其实。。。我从没看过网上的zkw费用流,是学长教我的,看起来就是改成了多路增广,有空我研究一下
哦哦……我网上的完全看不懂啊qwq
黄学长您t数组显然是开反了,,向我这种也开反了的那您的拍拍了一个小时还是挂啊
请问题解中的(不是程序中)k是什么?
可是我不明白:这道题为什么必须让cnt=1?
2333网络流的反向边啊
TAT为啥我觉得这道题的图可能有负环
这图没有环吧
考虑反向边
应该没有,否则不满足消圈定理
TAT为啥我觉得这道题的图可能有负环