大致题意
思路
费用流模板题,s向所有仓库连容量为ai费用为0的边,所有商店向t连流量为bj费用为0的边。仓库向商店连流量为INF费用为cij的边。跑费用流即可。坑点在于这题要求个最大和最小费用,跑完一遍网络流之后,原图的流量网络被改变,要重新建图。一个简单的方法是,考虑建图时候的正向反向边,将反向边的流量还给正向边,反向边置零即可恢复原图网络。
贴一下很久没用的费用流板子。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 10005
#define maxm 20006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,m;
int s,t;
struct node{int u,v,f,w;};
vector<node>ed;
vector<int>e[maxn];///边的标号
void add(int x,int y,int z,int w)
{
ed.push_back({x,y,z,w});
ed.push_back({y,x,0,-w});
int k=ed.size();///0---k-1
e[x].push_back(k-2);
e[y].push_back(k-1);
}
int a[maxn],p[maxn],dis[maxn];///a[i]:到i点的最大流量 p[i]:到i点所经过的边
bool inq[maxn];
pair<int,int> mincost_maxflow(int idt)
{
int mc=0,mf=0;
while(true){
memset(dis,idt*INF,sizeof(dis));
memset(a,0,sizeof(a));
queue<int>q;
q.push(s);
a[s]=INF;
dis[s]=0;
inq[s]=1;
while(!q.empty()){
int u=q.front();q.pop();inq[u]=0;
for(int i=0;i<e[u].size();i++){
int v=ed[e[u][i]].v;
int f=ed[e[u][i]].f;
int w=ed[e[u][i]].w;
if(idt*dis[v]>idt*(dis[u]+w)&&f>0){
dis[v]=dis[u]+w;
a[v]=min(f,a[u]);
p[v]=e[u][i];
if(inq[v]==0){
q.push(v);
inq[v]=1;
}
}
}
}
if(a[t]==0)break;
mf+=a[t];
mc+=dis[t]*a[t];
for(int i=t;i!=s;i=ed[p[i]].u){
ed[p[i]].f-=a[t];
ed[p[i]^1].f+=a[t];
}
}
return make_pair(mf,mc);
}
int main()
{
n=read();m=read();
s=n*m+1;t=s+1;
inc(i,1,n)add(s,i,read(),0);
inc(i,1,m)add(i+n,t,read(),0);
inc(i,1,n)inc(j,1,m)add(i,j+n,INF,read());
int ans1=mincost_maxflow(1).second;
for(int i=0;i<=ed.size()-2;i+=2){ed[i].f+=ed[i+1].f;ed[i+1].f=0;}///复原流量网络
int ans2=mincost_maxflow(-1).second;
printf("%d\n%d\n",ans1,ans2);
return 0;
}