图论(网络流):SCOI 2007 修车
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
输入
第一行有两个数M,N,表示技术人员数与顾客数。
接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。
输出
最小平均等待时间,答案精确到小数点后2位。
样例
repair.in
2 2
3 2
1 4
repair.out
1.50
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)
网上的题解好多都特别粗略,我走了好多弯路。
所以决定写详细一点:把每个修理工变为N个点,表示倒数第1~N个修理的车,为啥是倒数呢?因为不知道一个人究竟修了几辆车,又因为倒数第一的总比倒数第二的更优,费用流会优先倒数第一的,再倒数第二的,所以用倒数的可以很好地解决。多么的巧妙!!!然后是这样建图的:S向每个人的每个倒数第几维修的点连一条流量为1,费用为0的边;接着再新建N个点,代表N辆车,每个人的每个倒数第几维修的点向其连一条流量为1,费用为(当前是倒数第i个的i)*(第j个人修第k辆车的时间);最后由N辆车的向T连容量为1,费用为0的边。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 using namespace std; 6 const int INF=1000000000; 7 const int maxn=1010,maxm=400010; 8 int cnt=1,fir[maxn],nxt[maxm],to[maxm]; 9 int cap[maxm],val[maxm],dis[maxn],path[maxn]; 10 11 void add(int a,int b,int c,int v){ 12 nxt[++cnt]=fir[a];to[cnt]=b; 13 cap[cnt]=c;val[cnt]=v;fir[a]=cnt; 14 } 15 void addedge(int a,int b,int c,int v){ 16 add(a,b,c,v); 17 add(b,a,0,-v); 18 } 19 20 int S,T; 21 int vis[maxn]; 22 int Spfa(){ 23 deque<int>q; 24 memset(dis,127,sizeof(dis)); 25 memset(vis,0,sizeof(vis)); 26 q.push_front(S); 27 dis[S]=0;vis[S]=1; 28 while(!q.empty()){ 29 int x=q.front();q.pop_front();vis[x]=0; 30 for(int i=fir[x];i;i=nxt[i]) 31 if(cap[i]&&dis[x]+val[i]<dis[to[i]]){ 32 dis[to[i]]=val[i]+dis[x]; 33 path[to[i]]=i; 34 if(vis[to[i]])continue; 35 if(dis[to[i]]<dis[x]) 36 q.push_front(to[i]); 37 else 38 q.push_back(to[i]); 39 vis[to[i]]=1; 40 } 41 } 42 return dis[T]==dis[T+1]?0:dis[T]; 43 } 44 45 int Aug(){ 46 int p=T,f=INF; 47 while(p!=S){ 48 f=min(f,cap[path[p]]); 49 p=to[path[p]^1]; 50 } 51 p=T; 52 while(p!=S){ 53 cap[path[p]]-=f; 54 cap[path[p]^1]+=f; 55 p=to[path[p]^1]; 56 } 57 return f; 58 } 59 60 int MCMF(){ 61 int ret=0,d; 62 while(d=Spfa()) 63 ret+=Aug()*d; 64 return ret; 65 } 66 67 int n,m; 68 int a[maxn][maxn]; 69 int main(){ 70 freopen("scoi2007_repair.in","r",stdin); 71 freopen("scoi2007_repair.out","w",stdout); 72 scanf("%d%d",&m,&n); 73 S=0;T=n*m+n+1; 74 for(int i=1;i<=n;i++){ 75 addedge(n*m+i,T,1,0); 76 for(int j=1;j<=m;j++) 77 addedge(S,(i-1)*m+j,1,0); 78 } 79 for(int i=1;i<=n;i++) 80 for(int j=1;j<=m;j++) 81 scanf("%d",&a[i][j]); 82 83 for(int j=1;j<=m;j++) 84 for(int i=1;i<=n;i++) 85 for(int k=1;k<=n;k++) 86 addedge((i-1)*m+j,n*m+k,1,i*a[k][j]); 87 88 printf("%.2f\n",1.0*MCMF()/n); 89 return 0; 90 }
尽最大的努力,做最好的自己!