[bzoj1070] 修车

  这周学习了费用流,就写了几题。其中有一题就是bzoj上的修车,看起来很丧,交了6次都是除了样例全wa(事实证明样例说明不了什么,还会误导你……)。

  题目大意:有m个技术人员n辆车,一个技术人员只能同时修一辆车,每个技术人员修某一辆车都有特定的时间。求最小的等待时间。

  思路分析:这是一道费用流的题目,不看算法基本想不到是费用流。

       那么问题来了:怎么建图!看这个题目就像是把技术人员拆点。按题意建图的话,边权不是确定的,所以考虑拆成倒数第一次,倒数第二次……的n个结点。

       这样边权只要设为(之后的车数+1,也就是倒数的次数)*修车时间,因为包括自己之后每辆车都要等这么多时间。

       然后跑一边费用流。

       注意到它是二分图,所以可以用更高效的算法求解。而我比较蒻,只打了最简单的spfa。

  注意事项:我连wa了6次,是因为我没有认真看题,而样例m=n,n和m读反了就挂了3次(感谢falldream学长帮我debug)!!后面3次是没仔细调完就交还是wa。

  下面附上代码:

 1 #include<cstdio>
 2 using namespace std;
 3 const int inf=2147483647;
 4 int n,m,tot=1,mx,q[1010],d[1010],pree[1010],h[1010];
 5 struct edge{int to,nxt,cst,cap;}e[400010];
 6 bool vis[1010];
 7 int mn(int x,int y){return x>y?y:x;}
 8 void add(int fr,int to,int cst,int cap)
 9 {
10     e[++tot]={to,h[fr],cst,cap};h[fr]=tot;
11     e[++tot]={fr,h[to],-cst,0};h[to]=tot;
12 }
13 void init()
14 {
15     scanf("%d%d",&m,&n);
16     int a[10][61];
17     for(int i=1;i<=n;i++)
18         for(int j=1;j<=m;j++)
19             scanf("%d",&a[j][i]);
20     for(int j=1;j<=n;j++)
21     {
22         for(int i=1;i<=m;i++)
23         {
24             for(int k=1;k<=n;k++)
25                 add(j,i*n+k,a[i][j]*k,1);//从车向技术人员倒数第k辆连容量1费用k*修车费的边 
26             add(i*n+j,n*m+n+1,0,1);//从技术人员修的每辆车连向汇点容量1费用0的边 
27         }
28         add(0,j,0,1);//从源点连向每辆车容量1费用0的边 
29     }
30     mx=n;n=n*m+n+1;
31 }
32 bool spfa()
33 {
34     for(int i=1;i<=n;i++)d[i]=inf;
35     int l=0,r=1;q[1]=0;vis[0]=1;
36     while(l!=r)
37     {
38         int x=q[l=l==n?0:l+1];
39         for(int i=h[x];i;i=e[i].nxt)
40             if(e[i].cap&&e[i].cst+d[x]<d[e[i].to])
41             {
42                 int v=e[i].to;
43                 pree[v]=i;
44                 d[v]=d[x]+e[i].cst;
45                 if(!vis[v])
46                 {
47                     if(d[v]>d[l+1])q[r=r==n?0:r+1]=v;
48                     else q[l]=v,l=l==0?n:l-1;
49                     vis[v]=1;
50                 }
51             }
52         vis[x]=0;
53     }
54     return d[n]==inf?0:1;
55 }
56 float cf()
57 {
58     int cost=0,mm=0;
59     while(spfa())
60     {
61         int mi=inf;
62         for(int i=n;i;i=e[pree[i]^1].to)
63             mi=mn(mi,e[pree[i]].cap);
64         for(int i=n;i;i=e[pree[i]^1].to)
65         {
66             int ee=pree[i];
67             e[ee].cap-=mi;
68             e[ee^1].cap+=mi;
69         }
70         cost+=d[n]*mi;
71         mm+=mi;
72     }
73     return mm==mx?cost:0;
74 }
75 int main()
76 {
77     init();
78     printf("%.2f",cf()/mx);
79     return 0;
80 }

 

posted @ 2017-03-20 23:13  qrc  阅读(247)  评论(0编辑  收藏  举报