【Luogu】P2053修车(费用流)

  题目链接

  早上状态不好,虚树搞崩只好来刷网络流了qwq。

  (然后我犹豫几秒之后看了题解)

  使用拆点大法把工人拆成n*m个点,然后每个点代表每个时间段的工人,

  然后从车到每个工人点连一条边,权值是耽误的时间,就是这个车在这个时间段用这个工人所用的时间。

  然后跑费用流。

  (然后我太菜了费用流忘了怎么打了,回头一翻自己博客发现居然只是一周之前学的东西)

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
#define maxn 30000
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

inline int count(int i){    return i&1?i+1:i-1;    }

int dfn[maxn];
bool vis[maxn];
int Start,End;

struct Edge{
    int from,next,to,dis,val,flow;
}edge[maxn*5];
int head[maxn],num;
inline void addedge(int from,int to,int dis,int val){
    edge[++num]=(Edge){from,head[from],to,dis,val,0};
    head[from]=num;
}
inline void add(int from,int to,int dis,int val){
    addedge(from,to,dis,val);
    addedge(to,from,-dis,0);
}

struct Ans{
    int dis,val;
    Ans(){dis=val=0;}
};

int dis[maxn];
int pre[maxn];
int flow[maxn];

Ans spfa(){
    Ans ans;
    memset(dis,127/3,sizeof(dis));    int Max=dis[0];
    dis[Start]=0;    flow[Start]=0x7fffffff;
    queue<int>q;    q.push(Start);
    while(!q.empty()){
        int from=q.front();q.pop();vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(edge[i].dis+dis[from]>=dis[to]||edge[i].val==edge[i].flow)    continue;
            dis[to]=dis[from]+edge[i].dis;
            pre[to]=i;
            flow[to]=min(flow[from],edge[i].val-edge[i].flow);
            if(!vis[to]){
                vis[to]=1;
                q.push(to);
            }
        }
    }
    if(dis[End]==Max)    return ans;
    int now=End;    ans.val=flow[End];    ans.dis=dis[End];
    while(now!=Start){
        int ret=pre[now];
        edge[ret].flow+=flow[End];
        edge[count(ret)].flow-=flow[End];
        now=edge[ret].from;
    }
    return ans;
}

double ans;

int main(){
    int m=read(),n=read();End=maxn-2;
    for(int i=1;i<=n;++i)
        add(Start,i,0,1);
    for(int j=1;j<=m;++j)
        for(int i=1;i<=n;++i)    add((i-1)*m+n+j,End,0,1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int x=read();
            for(int k=1;k<=n;++k)
                add(i,(k-1)*m+j+n,k*x,1);
        }
    while(1){
        Ans now=spfa();
        if(!now.val)    break;
        ans+=now.dis*now.val;
    }
    printf("%.2lf",ans/n);
    return 0;
}

 

posted @ 2018-01-09 10:37  Konoset  阅读(124)  评论(0编辑  收藏  举报