首页 > 代码库 > bzoj1070: [SCOI2007]修车

bzoj1070: [SCOI2007]修车

网络流——最小费用流。

好久没写了板子都快忘了。将m个工人拆成n个点,点(i,j)表示让i工人在倒数第j辆车时去修连向这个点的车,那么显而易见代价为j*ti(后面的人要等)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 70
 4 #define M 15
 5 #define INF 1e9
 6 int n,m,cnt=2,ti[M][N],head[5005],p[5005],a[5005],ans,d[5005],S,T;
 7 bool vis[5005];
 8 queue<int>q;
 9 struct edges{
10     int fr,to,cap,flow,cost,next;
11 }e[100005];
12 void inser(int u,int v,int c,int co){
13     e[cnt]=(edges){u,v,c,0,co,head[u]};head[u]=cnt++;
14     e[cnt]=(edges){v,u,0,0,-co,head[v]};head[v]=cnt++;
15 }
16 bool spfa(){
17     memset(d,0x3f,sizeof(d));
18     q.push(S); d[S]=0; a[S]=INF;
19     while(!q.empty()){
20         int x=q.front(); q.pop(); vis[x]=0;
21         for(int i=head[x];i;i=e[i].next){
22             if(d[e[i].to]>d[x]+e[i].cost && e[i].cap>e[i].flow){
23                 d[e[i].to]=d[x]+e[i].cost; p[e[i].to]=i; a[e[i].to]=min(a[x],e[i].cap-e[i].flow);
24                 if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
25             }
26         }
27     }
28     return d[T]<INF;
29 }
30 void minc(){
31     ans+=a[T]*d[T];
32     int u=T;
33     while(u!=S){
34         e[p[u]].flow+=a[T];
35         e[p[u]^1].flow-=a[T];
36         u=e[p[u]].fr;
37     }
38 }
39 int main(){
40     scanf("%d%d",&m,&n);
41     S=0,T=n*m*2;
42     for(int i=1;i<=n;i++)
43        for(int j=1;j<=m;j++)
44           scanf("%d",&ti[j][i]);
45     for(int i=1;i<=m;i++)
46        for(int j=1;j<=n;j++)
47           inser((i-1)*n+j,T,1,0);
48     for(int i=1;i<=n;i++) inser(S,n*m+i,1,0);
49     for(int i=1;i<=n;i++)
50        for(int j=1;j<=m;j++)
51           for(int k=1;k<=n;k++)
52           inser(n*m+i,(j-1)*n+k,1,k*ti[j][i]);
53     while(spfa()) minc();
54     printf("%.2lf\n",(double)ans/n);
55     return 0;
56 }

 

bzoj1070: [SCOI2007]修车