题解 [SCOI2007]修车

题面

解析

这题要拆点。。

首先,证明一个式子:

设修理员M修了N辆车,

且修每辆车的时间为W1,W2....WN。

那么,这个修理员一共花的时间就为:W1*N+W2*(N-1)+...+WN*1。

因此,若i号修理员修第j辆车的时间为c[i][j],

将c[i][j]拆成1...n个点,

将其中第k个点与j号顾客(j号车)相连,

费用为c[i][j]*k,

最后将修理员与源点相连,顾客与汇点相连(反过来也可以),

流量为1,费用为0。

跑费用流就行了。

上AC代码:

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int INF=0x3f3f3f3f;
struct node{
    int to,next,v,w;
}e[100001];
struct hh{
    int fa,edge;
}pre[100001];
int n,m,s,t;
int c[101][101]/*第i辆车给第j个人修的时间*/;
int head[100001],cnt=1;
int d[100001],inq[100001],mi[100001];

void add(int x,int y,int v,int w){
    //printf("%d -> %d : %d
",x,y,w);
     e[++cnt].to=head[x];
    e[cnt].next=y;
    e[cnt].v=v;e[cnt].w=w;
    head[x]=cnt;
    e[++cnt].to=head[y];
    e[cnt].next=x;
    e[cnt].v=0;e[cnt].w=-w;
    head[y]=cnt;
}

bool spfa(){
    memset(d,0x3f,sizeof(d));
    memset(inq,0,sizeof(inq));
    memset(mi,0x3f,sizeof(mi));
    queue <int> que;
    que.push(s);
    d[s]=0;
    while(!que.empty()){
        int x=que.front();
        que.pop();
        inq[x]=0;
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(!e[i].v||d[k]<=d[x]+e[i].w) continue;
            d[k]=d[x]+e[i].w;
            pre[k].fa=x;pre[k].edge=i;
            mi[k]=min(mi[x],e[i].v);
            if(!inq[k]) que.push(k);
            inq[k]=1;
        }
    }
    return d[t]!=INF;
}

void EK(){
    int ans=0;
    while(spfa()){
        for(int i=t;i!=s;i=pre[i].fa){
            e[pre[i].edge].v-=mi[t];
            e[pre[i].edge^1].v+=mi[t];
        }
        ans+=d[t]*mi[t];
    }
    printf("%.2lf
",(double)((double)ans/(double)n));
}

int main(){
//    freopen("fixed.in","r",stdin);
//    freopen("fixed.out","w",stdout);
    m=read();n=read();
    s=1+(m+2)*n;t=2+(m+2)*n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            c[i][j]=read();
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            add(s,i+m*j,1,0);
            for(int k=1;k<=n;k++){
                add(i+m*j,k+m*n+n,1,c[k][i]*j);
            }
        }
    }
    for(int i=1;i<=n;i++){
        add(i+m*n+n,t,1,0);
    }
    EK();
    return 0;
}
原文地址:https://www.cnblogs.com/zsq259/p/10524912.html