[bzoj1070]修车
首先,源点向每一个车主连(1,0)的边,然后把每一个工人拆成n个点,第i个点表示修倒数第i辆车,那么这辆车对答案的代价就是time*i(time表示这辆车的时间,i表示倒数第i辆),就是说每一个车主向nm个工人的点连(1,time*i)的边。最后,每一个工人的点向汇点连(1,0)的边即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 #define oo 0x3f3f3f3f 5 struct ji{ 6 int nex,to,len,cost; 7 }edge[N*70]; 8 queue<int>q; 9 int E,n,m,t,head[N],from[N],d[N],vis[N]; 10 void add(int x,int y,int z,int w){ 11 edge[E].nex=head[x]; 12 edge[E].to=y; 13 edge[E].len=z; 14 edge[E].cost=w; 15 head[x]=E++; 16 if (E&1)add(y,x,0,-w); 17 } 18 bool spfa(){ 19 memset(vis,0,sizeof(vis)); 20 memset(d,oo,sizeof(d)); 21 d[0]=0; 22 q.push(0); 23 while (!q.empty()){ 24 int k=q.front(); 25 q.pop(); 26 vis[k]=0; 27 for(int i=head[k];i!=-1;i=edge[i].nex){ 28 int v=edge[i].to; 29 if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){ 30 d[v]=d[k]+edge[i].cost; 31 from[v]=i; 32 if (!vis[v]){ 33 vis[v]=1; 34 q.push(v); 35 } 36 } 37 } 38 } 39 return d[t]<oo; 40 } 41 int dinic(){ 42 int ans=0; 43 while (spfa()){ 44 ans+=d[t]; 45 for(int i=t;i;i=edge[from[i]^1].to){ 46 edge[from[i]].len--; 47 edge[from[i]^1].len++; 48 } 49 } 50 return ans; 51 } 52 int main(){ 53 scanf("%d%d",&m,&n); 54 memset(head,-1,sizeof(head)); 55 for(int i=1;i<=n;i++)add(0,i,1,0); 56 for(int i=1;i<=n;i++) 57 for(int j=1;j<=m;j++){ 58 scanf("%d",&t); 59 for(int k=1;k<=n;k++)add(i,j*n+k,1,t*k); 60 } 61 for(int i=1;i<=m;i++) 62 for(int j=1;j<=n;j++)add(i*n+j,n*m+n+1,1,0); 63 t=n*m+n+1; 64 printf("%.2f",dinic()*1.0/n); 65 }