题解:
很经典的网络流
对于每个厨师拆点分开统计 1倍 2倍 3倍
n(mp)^2 有点大
动态加边
即对于每个厨师有了i才会有i+1
不过好像还是有点卡常??
代码:
#include <bits/stdc++.h> using namespace std; #define INF 1e9 #define N 2000000 struct re{int a,b,c,from,flow,cost; }a[N]; int head[N],l,d[N],p[N],aa[N],dy1[N],dy2[N],tt[1000][1000],cnt; int n,m,s,t,maxa[N]; bool inq[N]; void arr(int x,int y,int z,int flow,int cost,int xx,int yy) {a[++l].a=head[x];a[l].b=y;a[l].c=z;head[x]=l;a[l].flow=flow;a[l].cost=cost;a[l].from=x;dy1[l]=xx;dy2[l]=yy; } bool bellmanford(int &flow,int &cost) {for (int i=1;i<=t;i++) d[i]=INF;memset(inq,0,sizeof(inq));d[s]=0; inq[s]=1; p[s]=0; aa[s]=INF;queue<int> q;q.push(s);while (!q.empty()){int x=q.front(); q.pop(); inq[x]=0;int u=head[x];while (u){int v=a[u].b;if (a[u].c>a[u].flow&&d[v]>d[x]+a[u].cost){d[v]=d[x]+a[u].cost;p[v]=u;aa[v]=min(aa[x],a[u].c-a[u].flow);if (!inq[v]) q.push(v),inq[v]=1;}u=a[u].a;}}if (d[t]==INF) return(0);flow+=aa[t];cost+=d[t]*aa[t];int x=t;while (x!=s){int u=p[x];a[u].flow+=aa[t];if (u%2) a[u+1].flow-=aa[t];else a[u-1].flow-=aa[t];if (dy2[u]==maxa[dy1[u]]){int y=dy1[u];maxa[y]++;cnt++;for (int i=1;i<=n;i++){arr(i,cnt,1,0,tt[i][y]*maxa[y],y,maxa[y]);arr(cnt,i,0,0,-tt[i][y]*maxa[y],y,maxa[y]);}arr(cnt,t,1,0,0,0,0);arr(t,cnt,0,0,0,0,0);}//cout<<a[u].from<<" "<<a[u].b<<" "<<a[u].cost<<" "<<a[u].flow<<endl;x=a[u].from;}//cout<<endl;return 1; } int flow,cost; void mincost() {while (bellmanford(flow,cost)); } int pp[N]; int main() {std::ios::sync_with_stdio(false);cin>>n>>m;int sum=0;for (int i=1;i<=n;i++){cin>>pp[i]; sum+=pp[i];}for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)cin>>tt[i][j];s=0; t=n+m*sum+1;for (int i=1;i<=n;i++)arr(s,i,pp[i],0,0,0,0),arr(i,s,0,0,0,0,0);maxa[0]=INF;for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){maxa[j]=1;cnt=n+j;arr(i,cnt,1,0,tt[i][j],j,1);arr(cnt,i,0,0,-tt[i][j],j,1);}for (int i=1;i<=m;i++){cnt=n+i;arr(cnt,t,1,0,0,0,0);arr(t,cnt,0,0,0,0,0);}cnt=n+m; /* for (int i=1;i<=l;i++){cout<<a[i].b<<" "<<a[i].from<<" "<<a[i].c<<" "<<a[i].cost<<endl;} */mincost();cout<<cost<<endl;return 0; }