[SCOI2007] 修车

考虑将修车师傅放在一边,顾客放在一边。

对于第 \(i\) 辆车,让第 \(j\) 个修车师傅来修,放在了倒数第 \(l\) 个,那么他产生的贡献即为 \(t_{i,j}\times l\)

我们可以将每个修车师傅拆成 \(n\) 个点,第 \(l\) 个点表示修车师傅的倒数第 \(l\) 个位置,跑费用流即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1005,M=1e5+5;
int n,m,s,t,k=1,h[N],vis[N];
int to[M],nxt[M],w[M],f[M];
int lst[N],flw[N],dis[N];
void add(int x,int y,int z,int a){
    w[++k]=z;f[k]=a;to[k]=y;
    nxt[k]=h[x];h[x]=k;
    f[++k]=-a;to[k]=x;
    nxt[k]=h[y];h[y]=k;
}queue<int>q;
int spfa(){
    while(q.size()) q.pop();
    memset(lst,-1,sizeof(lst));
    memset(vis,0,sizeof(vis));
    memset(dis,127,sizeof(dis));
    flw[s]=1e9;dis[s]=0;q.push(s);
    while(q.size()){
        int x=q.front();
        q.pop();vis[x]=0;
        for(int i=h[x];i;i=nxt[i]){
            int y=to[i],vl=w[i];
            if(vl&&dis[y]>dis[x]+f[i]){
                lst[y]=i;
                flw[y]=min(flw[x],vl);
                dis[y]=dis[x]+f[i];
                if(!vis[y])
                    q.push(y),vis[y]=1;
            }
        }
    }return lst[t]!=-1;
}int mxflw,mncst;
void MCMF(){
    while(spfa()){
        mxflw+=flw[t];
        mncst+=dis[t]*flw[t];
        for(int i=t;i!=s;i=to[lst[i]^1])
            w[lst[i]]-=flw[t],w[lst[i]^1]+=flw[t];
    }
}signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>m>>n;t=n+n*m+1;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            add(s,i*n+j,1,0);
    for(int i=1;i<=n;i++) add(i,t,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int x;cin>>x;
            for(int l=1;l<=n;l++)
                add(j*n+l,i,1,l*x);
        }
    MCMF();printf("%.2lf",mncst*1.0/n);
    return 0;
}//spfa:它没有死透
posted @ 2024-05-19 11:51  长安一片月_22  阅读(6)  评论(0编辑  收藏  举报