前言
n和m搞反调半天系列
正题
AC记录链接:
https://www.luogu.org/record/show?rid=7949136
大意
又m个员工,n辆车,第j个员工修第i辆车需要T[i][j]的时间,求分配让顾客平均等待时间最短。
解题思路
首先先假设一个修车工要修1−w1−w个人,那么对等待时间就要加上
t[1]∗w+t[2]∗(w−1)...+t[w−1]∗2+t[w]t[1]∗w+t[2]∗(w−1)...+t[w−1]∗2+t[w]
那我们可以将m个修车工拆成m*n个人表示第m个人第n次修车,然后可以将顾客和修车工建立完全二分图,权值为
权值∗第几次权值∗第几次
之后将原点连车,工人连汇点。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct line{int to,w,c,next;
}a[100081];
int tot,n,m,s,t,f[5001],ls[5001],tail,answer;
int state[5001],x,y,w,c,ans,head,pre[5001];
bool v[5001];
void addl(int x,int y,int w,int c)
{a[++tot].to=y;a[tot].w=w;a[tot].c=c;a[tot].next=ls[x];ls[x]=tot;a[++tot].to=x;a[tot].w=0;a[tot].c=-c;a[tot].next=ls[y];ls[y]=tot;
}
bool spfa()
{for (int i=1;i<=t;i++)f[i]=2147483647;head=0;tail=1;v[s]=true;state[1]=s;f[s]=0;while (head!=tail){head=head%t+1;int x=state[head];for (int q=ls[x];q;q=a[q].next){int y=a[q].to;if (a[q].w&&f[x]+a[q].c<f[y]){f[y]=f[x]+a[q].c;pre[y]=q;if (!v[y]){v[y]=true;tail=tail%t+1;state[tail]=y;}}}v[x]=false;}if (f[t]==2147483647) return 0;else return 1;
}
void upway()
{int now;ans+=f[t];now=t;answer+=1;while (now!=s){a[pre[now]].w--;a[pre[now]^1].w++;now=a[pre[now]^1].to;}
}
int main()
{tot=1;scanf("%d%d",&m,&n);s=m*n+n+1;t=m*n+n+2;for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){scanf("%d",&x);for (int k=1;k<=n;k++)addl(n*m+i,~-(j)*n+k,1,k*x);//连接}for (int i=n*m+1;i<=n*m+n;i++) addl(s,i,1,0);//连原点for (int i=1;i<=n*m;i++)addl(i,t,1,0);//连汇点while (spfa()){upway();}printf("%.2lf",1.0*ans/n);
}