【费用流】[BZOJ1070]/[HYSBZ1070]修车
题目
分析:将一个技术人员拆成n个点,分别和车连边,第j个技术人员拆成的第k个点修理第i辆车的费用为k*tm[i][j].
当一辆车是这个技术人员修理的倒数第k辆车时,它对等待时间的总数贡的献为k*tm[i][j].
最后,将总数/n即可.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 70
#define MAXM 15
#define INF 0x7f7f7f7f
using namespace std;
queue<int>q;
struct node{
int u,v,wt,cap;
node *next,*back;
}*adj[MAXN*MAXM+10],edge[MAXN*MAXM*MAXN*3+10],*ecnt=edge,*pre[MAXN*MAXM+MAXN+10];
int n,m,tm[MAXN+5][MAXM+5],S,T,dist[MAXN*MAXM+MAXN+10],ans;
bool vis[MAXN*MAXM+MAXN+10];
void addedge(int u,int v,int wt,int cap){
node *p=++ecnt;
p->v=v;
p->wt=wt;
p->cap=cap;
p->next=adj[u];
adj[u]=p;
p=p->back=++ecnt;
p->back=ecnt-1;
p->v=u;
p->wt=-wt;
p->cap=0;
p->next=adj[v];
adj[v]=p;
}
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
void read(){
Read(m),Read(n);
int i,j,k;
T=n*m+n+1;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
Read(tm[i][j]);
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
addedge((j-1)*n+k,i+n*m,k*tm[i][j],1);
for(k=1;k<=n;k++)
for(j=1;j<=m;j++)
addedge(S,(j-1)*n+k,0,1);
for(i=1;i<=n;i++)
addedge(i+n*m,T,0,1);
}
bool spfa(){
memset(dist,0x7f,sizeof dist);
memset(pre,0,sizeof pre);
q.push(S);
dist[S]=0;
int u,v;
vis[S]=1;
while(!q.empty()){
u=q.front();
q.pop();
vis[u]=0;
for(node *p=adj[u];p;p=p->next){
v=p->v;
if(p->cap>0&&dist[u]+p->wt<dist[v]){
dist[v]=dist[u]+p->wt;
pre[v]=p;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
if(dist[T]==INF)
return 0;
return 1;
}
void mcmf(){
int u,delta;
while(spfa()){
delta=INF;
for(u=T;u!=S;u=pre[u]->back->v)
delta=min(delta,pre[u]->cap);
for(u=T;u!=S;u=pre[u]->back->v){
pre[u]->cap-=delta;
pre[u]->back->cap+=delta;
ans+=pre[u]->wt*delta;
}
}
}
int main()
{
read();
mcmf();
printf("%.2lf\n",1.0*ans/n);
}