图论(网络流):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 }

 

posted @ 2016-07-11 20:41  TenderRun  阅读(301)  评论(0编辑  收藏  举报