版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/84418480
正题
给出m个师傅,n台车,并给出每个师傅各个车的时间,现在要使得,n辆车一起来,等待时间最短。
我们来观察一个师傅所消耗的等待时间。m个师傅所消耗的总等待时间就是车主的总等待时间。
对于第a个师傅,修的车的序列是,那么总等待时间就是,因为第i个车要被自己和后面的车等待,所以会被算tot-i+1次。
那么建图就是分显而易见了,对于m个师傅,每个师傅拆n个点,第a个师傅的第i个点表示的是第a个师傅修倒数第i辆车。那么n个点表示车。
倒数第1辆车只会被自己等待,所以从这点连向每一辆车j,表示可以修这一辆车,流量为1,费用为。
倒数第2辆车会被等待两次,所以从这个点连向每一辆车j,流量为1,费用为
......
那么最后我们从源点流量为1,费用为0的边向所有时间段的师傅。从每一辆车连流量为1,费用为0的边向汇点。
最小费用最大流跑一下。
Done.
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct edge{
int x,y,next,c,cos;
}s[100010];
int n,m;
int len=1;
int begin,end;
int d[1210],mmin[1210],last[1210],first[1210];
bool tf[1210];
queue<int> f;
void ins(int x,int y,int c,int cos){
len++;
s[len]=(edge){x,y,first[x],c,cos};first[x]=len;
len++;
s[len]=(edge){y,x,first[y],0,-cos};first[y]=len;
}
bool SPFA(int &cost,int&flow){
memset(d,63,sizeof(d));
memset(tf,false,sizeof(tf));
memset(mmin,63,sizeof(mmin));
memset(last,0,sizeof(last));
f.push(begin);d[begin]=0;tf[begin]=true;
while(!f.empty()){
int x=f.front();f.pop();tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(d[y]>d[x]+s[i].cos && s[i].c>0){
mmin[y]=min(mmin[x],s[i].c);
d[y]=d[x]+s[i].cos;
last[y]=i;
if(!tf[y]){
tf[y]=true;
f.push(y);
}
}
}
}
if(d[end]==d[end+1]) return false;
cost+=d[end]*mmin[end];
flow+=mmin[end];
int now=end;
while(now!=begin){
s[last[now]].c-=mmin[end];
s[last[now]^1].c+=mmin[end];
now=s[last[now]].x;
}
return true;
}
void MCMF(){
int cost=0,flow=0;
while(SPFA(cost,flow));
printf("%.2lf\n",(double)cost/n);
}
int main(){
scanf("%d %d",&m,&n);
begin=0,end=n*m+n+1;
int type=n*m;
int c;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&c);
for(int k=1;k<=n;k++) ins((j-1)*n+k,type+i,1,k*c);
}
}
for(int i=1;i<=type;i++) ins(begin,i,1,0);
for(int i=type+1;i<end;i++) ins(i,end,1,0);
MCMF();
}