题目描述:这里
题面已经提示我们这是费用流了
那么由源点向所有仓库连边,容量为仓库原有货物量,费用为0
然后由所有零售商店向汇点连边,容量为一个零售商店的需求量,费用为0
最后由仓库向零售商店连边,容量正无穷(由于源点和汇点的限制,所以不会出现不合法情况),费用为题给费用
然后跑费用流就得到了最小费用
至于最大费用,按套路所有费用取反后再跑一遍费用流即可
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> using namespace std; const int inf=0x3f3f3f3f; struct Edge { int next; int to; int val; int pri; }edge[40005]; int head[255]; int dis[255]; int pre[255]; int fa[255]; bool used[255]; int lim[255]; int v1[255]; int v2[255][255]; int cnt=1; int st,ed; int n,m; void init() { memset(head,-1,sizeof(head)); memset(edge,0,sizeof(edge)); cnt=1; } void add(int l,int r,int w,int v) { edge[cnt].next=head[l]; edge[cnt].to=r; edge[cnt].val=w; edge[cnt].pri=v; head[l]=cnt++; } int ide(int x) { return (x&1)?x+1:x-1; } bool spfa() { memset(dis,0x3f,sizeof(dis)); memset(used,0,sizeof(used)); memset(lim,0,sizeof(lim)); dis[st]=0; pre[ed]=-1; lim[st]=inf; used[st]=1; queue <int> M; M.push(st); while(!M.empty()) { int u=M.front(); M.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int to=edge[i].to; if(edge[i].val&&dis[to]>dis[u]+edge[i].pri) { lim[to]=min(lim[u],edge[i].val); dis[to]=dis[u]+edge[i].pri; pre[to]=i,fa[to]=u; if(!used[to])used[to]=1,M.push(to); } } used[u]=0; } return pre[ed]!=-1; } int EK() { int maxw=0,minv=0; while(spfa()) { maxw+=lim[ed]; minv+=lim[ed]*dis[ed]; int temp=ed; while(temp!=st) { edge[pre[temp]].val-=lim[ed]; edge[ide(pre[temp])].val+=lim[ed]; temp=fa[temp]; } } return minv; } int main() { init(); scanf("%d%d",&n,&m); st=m+n+1,ed=m+n+2; for(int i=1;i<=n;i++) { scanf("%d",&v1[i]); add(st,i,v1[i],0); add(i,st,0,0); } for(int i=1;i<=m;i++) { scanf("%d",&v1[i+n]); add(i+n,ed,v1[i+n],0); add(ed,i+n,0,0); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&v2[i][j+n]); add(i,j+n,inf,v2[i][j+n]); add(j+n,i,0,-v2[i][j+n]); } } printf("%d ",EK()); init(); for(int i=1;i<=n;i++) { add(st,i,v1[i],0); add(i,st,0,0); } for(int i=1;i<=m;i++) { add(i+n,ed,v1[i+n],0); add(ed,i+n,0,0); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { add(i,j+n,inf,-v2[i][j+n]); add(j+n,i,0,v2[i][j+n]); } } printf("%d ",-EK()); return 0; }