【bzoj 1070】修车(费用流)

传送门biu~
把每个工人拆成 n 个点,源点连每个n×m的点,流量为 1 ,费用为0 n×m 的点连每辆车,流量为 1 ,费用为timei,j×k。每辆车连汇点,流量为 1 ,费用为0。因为每个工人修车所带来的影响是它和它后面的车的等待时间都增加了 timei,j

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n,m,S,T,cost,t[65][15];
int head[1005],nex[100005],to[100005],cap[100005],val[100005],tp=1;
int fir[1005],dis[1005];
bool b[1005];
inline void add(int x,int y,int c,int v){
    nex[++tp]=head[x];
    head[x]=tp;
    to[tp]=y;
    cap[tp]=c;
    val[tp]=v;
}
inline void Insert(int x,int y,int c,int v){add(x,y,c,v);add(y,x,0,-v);}
inline bool spfa(){
    queue<int>q;
    for(int i=S;i<=T;++i)       dis[i]=INF,b[i]=false;
    dis[S]=0;q.push(S);
    while(!q.empty()){
        int x=q.front();q.pop();b[x]=false;
        for(int i=head[x];i;i=nex[i]){
            if(cap[i] && dis[x]+val[i]<dis[to[i]]){
                dis[to[i]]=dis[x]+val[i];
                if(!b[to[i]]){
                    q.push(to[i]);
                    b[to[i]]=true;
                }
            }
        }
    }
    return dis[T]^INF;
}
int dfs(int x,int now){
    if(x==T || !now){
        cost+=now*dis[T];
        return now;
    }   
    int c=0;
    b[x]=true;
    for(int &i=fir[x];i;i=nex[i]){
        if(!b[to[i]] && cap[i] && dis[to[i]]==dis[x]+val[i]){
            int f=dfs(to[i],min(now,cap[i]));
            now-=f;
            cap[i]-=f;
            cap[i^1]+=f;
            c+=f;
            if(!now)    break;
        }
    }
    return c;
}
inline int Dinic(){
    int c=0;
    while(spfa()){
        for(int i=S;i<=T;++i)       fir[i]=head[i];
        c+=dfs(S,INF);
    }
    return c;
}
int main(){
    scanf("%d%d",&n,&m);S=0;T=n*m+m+1;
    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)         Insert(S,i,1,0);
    for(int i=n*m;i<=n*m+m;++i)     Insert(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)
                Insert((i-1)*m+j,n*m+k,1,t[k][i]*j);
    Dinic();
    printf("%.2lf",(double)cost/m);
    return 0;           
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值