算法:
最小费用最大流,最大费用最大流
建图方式:
源点与仓库相连,流量为a[i],费用0
汇点与商店相连,流量为b[i],费用为0
仓库与商店相连,流量无限,费用为c[i][j]
小技巧
最大费用最大流转换成最小费用最大流,方法就是建图的时候把费用变成相反数跑最小费用最大流,最后答案取相反数即可
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 1000000007
using namespace std;
int st,lt;
int head[20001],to[20001],nxt[20001],tot=1,flow[20001],value[20001];
int dis[20001],vis[20001],from[20001],pre[20001];
int ansflow,anscost;
queue<int>q;
int m,n;
void add(int x,int y,int f,int v)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
flow[tot]=f;
pre[tot]=x;
value[tot]=v;
return;
}
int ck[101],sd[101];
int jg[101][101];
bool spfa(int s)
{
for(int i=0;i<=n+m+4;i++)
dis[i]=inf;
memset(vis,0,sizeof(vis));
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=nxt[i])
{
int p=to[i];
if(flow[i]>0&&dis[p]>dis[x]+value[i])
{
from[p]=i;
dis[p]=dis[x]+value[i];
if(!vis[p])
{
q.push(p);
vis[p]=1;
}
}
}
}
if(dis[lt]>=inf)return 0;else return 1;
}
void mcf()
{
int x=inf;
for(int i=from[lt];i;i=from[pre[i]])
{
x=min(x,flow[i]);
}
ansflow+=x;
for(int i=from[lt];i;i=from[pre[i]])
{
flow[i]-=x;
flow[i^1]+=x;
anscost+=value[i]*x;
}
}
int main()
{
scanf("%d%d",&m,&n);
lt=m+n+1;
st=m+n+2;
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++)
{
scanf("%d",&ck[i]);
add(st,i,ck[i],0);
add(i,st,0,0);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&sd[i]);
add(i+m,lt,sd[i],0);
add(lt,i+m,0,0);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&jg[i][j]);
add(i,j+m,inf,jg[i][j]);
add(j+m,i,0,-jg[i][j]);
}
while(spfa(st))
{
mcf();
}
printf("%d",anscost);
memset(head,0,sizeof(head));
memset(nxt,0,sizeof(nxt));
memset(to,0,sizeof(to));
memset(from,0,sizeof(from));
anscost=0,ansflow=0;
for(int i=1;i<=m;i++)
{
add(st,i,ck[i],0);
add(i,st,0,0);
}
for(int i=1;i<=n;i++)
{
add(i+m,lt,sd[i],0);
add(lt,i+m,0,0);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
add(i,j+m,inf,-jg[i][j]);
add(j+m,i,0,jg[i][j]);
}
while(spfa(st))
{
mcf();
}
printf("\n%d",-anscost);
return 0;
}