修车——网络流——费用流

  这题很明显的是费用流了,关键是在于建图。其实,网络流的关键也是难点就在于建图。

  n个师傅,m个车……

  根据题意,需要把每个师傅拆成m个点,每辆车再向这些点连接,再来个超级源点S,超级汇点T即可。

  代码很丑……

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int h[1210],d[1210],used[1210],que[100010],last[1210];
int k=1,INF=0x7fffffff,ans=0;
inline int read(){
    int t=1,num=0;
    char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}
    return num*t;
}
struct edge{
    int to,cap,cost,next;
}g[60010];
void add(int f,int t,int c1,int c2){
    g[++k].next=h[f];h[f]=k;g[k].to=t;g[k].cap=c1;g[k].cost=c2;
    g[++k].next=h[t];h[t]=k;g[k].to=f;g[k].cap=0;g[k].cost=-c2;
}
bool spfa(int s,int t){
    memset(last,0,sizeof(last));
    memset(d,127/3,sizeof(d));INF=d[0];
    memset(used,0,sizeof(used));
    int tail,head;
    head=tail=50002;
    que[head]=s;used[s]=1;d[s]=0;
    while(head>=tail){
        int x=que[tail++];
        for(int i=h[x];i;i=g[i].next){
            if(g[i].cap&&d[x]+g[i].cost<d[g[i].to]){
                d[g[i].to]=d[x]+g[i].cost;
                last[g[i].to]=i;
                if(!used[g[i].to]){
                    if(d[g[i].to]<d[que[tail]])que[--tail]=g[i].to;
                    else que[++head]=g[i].to;
                    used[g[i].to]=1;
                }
            }
        }
        used[x]=0;
    }
    return d[t]!=INF;
}
void mcf(int t){
    int minn=INF;
    for(int i=last[t];i;i=last[g[i^1].to])minn=min(minn,g[i].cap);
    for(int i=last[t];i;i=last[g[i^1].to]){
        ans+=g[i].cost*minn;
        g[i].cap-=minn;
        g[i^1].cap+=minn;
    }
}
int main()
{
    int n,m,a[70][10];m=read();n=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
    int s=n*m+n+1,t=n*m+n+2;
    for(int i=1;i<=n;i++)add(s,i,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=n;k++)
                add(i,j*n+k,1,k*a[i][j]);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            add(i*n+j,t,1,0);
    while(spfa(s,t))mcf(t);
    double Ans=(double)(ans);
    printf("%.2lf",Ans/n);
    return 0;
}

本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。

转载于:https://www.cnblogs.com/Yzyet/p/6624248.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值