题意:
给你n个要修的车,m个人
问你修完他们的总时间/n等于几
题解:
最小费用最大流
把每个工人拆成N个点。记为A[i,j]表示第i个工人修倒数第j辆车。
每个车跟所有N*M个工人拆出的点连边。流量为1,费用为time[i,j]*k。
源和每辆车连边,N*M个点和汇连边,流量都为1,费用同为0。
最小费用最大流即可
代码:
#include<bits/stdc++.h> #define inf 0x7fffffff #define T 601 using namespace std; int n,m,cnt=1,ans,t[61][10]; int d[605],q[605],from[605],head[605]; bool mark[605]; struct edge{int from,to,next,c,v;}e[100001]; void ins(int u,int v,int w,int c) { cnt++; e[cnt].from=u;e[cnt].to=v; e[cnt].next=head[u];head[u]=cnt; e[cnt].c=c;e[cnt].v=w; } void jb(int u,int v,int w,int c){ins(u,v,w,c);ins(v,u,0,-c);} bool spfa() { memset(mark,0,sizeof(mark)); for (int i=0;i<=T;i++)d[i]=inf; int t=0,w=1; d[T]=0;mark[T]=1;q[0]=T; while (t!=w) { int now=q[t];t++; if(t==T)t=0; for (int i=head[now];i;i=e[i].next) if (e[i^1].v&&d[e[i].to]>d[now]-e[i].c) { d[e[i].to]=d[now]-e[i].c; if (!mark[e[i].to]) { mark[e[i].to]=1; q[w++]=e[i].to; if(w==T)w=0; } } mark[now]=0; } if (d[0]==inf)return 0; return 1; } int dfs(int x,int f) { if(x==T){mark[T]=1;return f;} int used=0,w; mark[x]=1; for (int i=head[x];i;i=e[i].next) if (!mark[e[i].to]&&e[i].v&&d[x]-e[i].c==d[e[i].to]) { w=f-used; w=dfs(e[i].to,min(e[i].v,w)); ans+=w*e[i].c; e[i].v-=w;e[i^1].v+=w; used+=w; if (used==f)return f; } return used; } void zkw() { while(spfa()) { mark[T]=1; while(mark[T]) { memset(mark,0,sizeof(mark)); dfs(0,inf); } } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) for (int j=1;j<=n;j++)scanf("%d",&t[i][j]); for (int i=1;i<=n*m;i++)jb(0,i,1,0); for (int i=n*m+1;i<=n*m+m;i++)jb(i,T,1,0); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=1;k<=m;k++)jb((i-1)*m+j,n*m+k,1,t[k][i]*j); zkw(); printf("%.2lf",(double)ans/m); return 0; }