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); }