[bzoj1070]修车

蹲街弑〆低调 提交于 2019-11-27 09:52:08

首先,源点向每一个车主连(1,0)的边,然后把每一个工人拆成n个点,第i个点表示修倒数第i辆车,那么这辆车对答案的代价就是time*i(time表示这辆车的时间,i表示倒数第i辆),就是说每一个车主向nm个工人的点连(1,time*i)的边。最后,每一个工人的点向汇点连(1,0)的边即可。

 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 }
View Code

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!