#费用流,EK#JZOJ 3370 洛谷 2050 美食节

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/87255605

分析

看到这个题目,就想起了修车
建图时源点与菜品连流量为需求量费用为0的边,每个厨子在当时所做的菜的时刻与汇点连流量为1费用为0的边,菜品与每个厨子做的菜的时刻连流量为1费用为时间的边,但是这样会T掉,那怎么办,想到EK每次只跑一条增广路,那么可以动态加边,如果让厨子做完一道菜,那么就让它继续做菜,然后发现T了一个点,发现点数量开小了1,害得我改了几天


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#define min(a,b) ((a)<(b)?(a):(b))
#define rr register
using namespace std;
struct node{int y,w,f,next;}e[80101]; bool v[80101];
int n,m,ans,s,t,k=1,cnt,ls[80101],dis[80101],pre[80101],pay[41][101];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void add(int x,int y,int w,int f){
    e[++k]=(node){y,w,f,ls[x]}; ls[x]=k;
    e[++k]=(node){x,0,-f,ls[y]};ls[y]=k;
}
inline signed spfa(){
    rr queue<int>q; memset(dis,127/3,sizeof(dis));
    memset(v,0,sizeof(v));
    dis[s]=0; v[s]=1; q.push(s);
    while (q.size()){
        rr int x=q.front(); q.pop();
        for (rr int i=ls[x];i;i=e[i].next)
        if (e[i].w>0&&dis[e[i].y]>dis[x]+e[i].f){
            dis[e[i].y]=dis[x]+e[i].f;
            pre[e[i].y]=i;
            if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
        }
        v[x]=0;
    }
    return dis[t]<707406378;
}
inline void update(){
    rr int bk=t,minx=dis[0];
    while (bk!=s) minx=min(minx,e[pre[bk]].w),bk=e[pre[bk]^1].y;
    ans+=minx*dis[bk=t];
    while (bk!=s) e[pre[bk]].w-=minx,e[pre[bk]^1].w+=minx,bk=e[pre[bk]^1].y;
    bk=e[pre[t]^1].y;
    add(bk+1,t,1,0);
    for (rr int i=1;i<=n;++i)
        add(i,bk+1,1,pay[i][(bk-n)/cnt+1]*((bk-n)%cnt+1));
}
signed main(){
    n=iut(); m=iut();
    for (rr int i=1;i<=n;++i){
        rr int x=iut(); cnt+=x;
        add(n+1,i,x,0);
    }
    s=n+cnt*m+2,t=s+1; ls[s]=ls[n+1]; ls[n+1]=0;
    for (rr int i=3;i<=k;i+=2) if (e[i].y==n+1) e[i].y=s;
    for (rr int i=1;i<=n;++i)
    for (rr int j=1;j<=m;++j)
        add(i,(j-1)*cnt+1+n,1,pay[i][j]=iut());
    for (rr int j=1;j<=m;++j) add((j-1)*cnt+n+1,t,1,0);
    while (spfa()) update();
    return !printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/87255605