[费用流]luogu P2050 美食节

https://www.luogu.org/problemnew/show/P2050

分析

网络流的构图都好神仙啊%%%

我们设i为第i个菜,从原点向i连流量为需求量的边

然后动态加点,每次加入第j个城市倒数第k做第i个菜,其边权为k*t[j][i],流量均为一

优化:只为每次增广后的那个厨师加点

 

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <queue>
using namespace std;
struct Pipe {
    int v,c,w,nx;
}g[10000010];
int cnt=1,list[100050];
int dis[100050],vis[100050],f[100050],nex[100050];
int w[101][41];
int n,m,s,t,ans,sum,l;

void Add(int u,int v,int c,int w) {
    g[++cnt]=(Pipe){v,c,w,list[u]};list[u]=cnt;
    g[++cnt]=(Pipe){u,0,-w,list[v]};list[v]=cnt;
}

bool SPFA() {
    queue<int> q;
    while (!q.empty()) q.pop();
    memset(vis,0,sizeof vis);memset(dis,0x3f,sizeof dis);
    q.push(s);vis[s]=1;dis[s]=0;
    while (!q.empty()) {
        int u=q.front();q.pop();
        for (int i=list[u];i;i=g[i].nx)
            if (g[i].c&&dis[g[i].v]>dis[u]+g[i].w) {
                dis[g[i].v]=dis[u]+g[i].w;f[g[i].v]=i;
                if (!vis[g[i].v]) q.push(g[i].v);
                vis[g[i].v]=1;
            }
        vis[u]=0;
    }
    return dis[t]!=0x3f3f3f3f;
}

void MCF() {
    int x=t,mf=2147483647;
    while (f[x]) {
        mf=min(mf,g[f[x]].c);
        x=g[f[x]^1].v;
    }
    x=t;ans+=dis[t];
    while (f[x]) {
        g[f[x]].c-=mf;g[f[x]^1].c+=mf;
        x=g[f[x]^1].v;
    }
}

void Dinic() {
    while (SPFA()) {
        MCF();
        int need=nex[g[f[t]^1].v];
        Add(need,t,1,0);
        for (int i=1;i<=n;i++) Add(i,need,1,((int)(need-n)/m+((need-n)%m!=0))*w[(need-n-1)%m+1][i]);
    }
}

int main() {
    scanf("%d%d",&n,&m);s=0;t=80049;
    for (int i=1,a;i<=n;i++) scanf("%d",&a),Add(s,i,a,0),sum+=a;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) scanf("%d",&w[j][i]),Add(i,n+j,1,w[j][i]);
    for (int i=1;i<=m;i++) Add(n+i,t,1,0);
    for (int i=1;i<=sum;i++)
        for (int j=1;j<=m;j++) nex[n+(i-1)*m+j]=n+i*m+j;
    Dinic();
    printf("%d",ans);
}
View Code

 

posted @ 2019-07-08 07:33  Vagari  阅读(138)  评论(0编辑  收藏  举报