《数学一本通》例题。直接最小费用最大流。第二问最大费用最大流可以让费用取反然后跑最小费用最大流。
之后研究过一下这个问题如果销量和产量不等的话可以建一个辅助点费用为0即可。
#include
#include
#include
#include
#include
#include
#define inf 20021225
#define maxm 20010
#define maxn 110
using namespace std;
struct Edge{int to,lt,f,v;}e[maxm<<1];
int in[maxn<<1],cnt=1,a[maxn],b[maxn],h[maxn<<1],all;
int s,t,dis[maxn<<1],tot,ans,c[maxn][maxn],na[maxn],nb[maxn];
bool iq[maxn<<1],vis[maxn<<1];
void addedge(int x,int y,int f,int v)
{
e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;e[cnt].f=f;e[cnt].v=v;
e[++cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;e[cnt].f=0;e[cnt].v=-v;
}
queue q;
bool spfa()
{
while(!q.empty()) q.pop();
memset(iq,0,sizeof(iq));
for(int i=1;i<=tot;i++) dis[i]=inf;
dis[t]=0;iq[t]=1;q.push(t);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=in[u];i;i=e[i].lt)
{
if(e[i^1].f&&dis[e[i].to]>dis[u]+e[i^1].v)
{
dis[e[i].to]=dis[u]+e[i^1].v;
if(!iq[e[i].to])
{
iq[e[i].to]=1;
q.push(e[i].to);
}
}
}
iq[u]=0;
}
return dis[t]==inf?0:1;
}
int dfs(int x,int f)
{
vis[x]=1;
if(x==t)
return f;
int us=0;
for(int i=h[x];i;i=e[i].lt)
{
int v=e[i].to;
if(!vis[v]&&e[i].f&&dis[x]==dis[v]+e[i].v)
{
int cur=dfs(v,min(f-us,e[i].f));
if(cur)
{
us+=cur;e[i].f-=us;e[i^1].f+=us;
ans+=cur*e[i].v;
if(f==us) return f;
}
if(e[i].f) h[x]=i;
}
}
return us;
}
void link(int m,int n)
{
s=++tot;t=++tot;
for(int i=1;i<=m;i++)
{
na[i]=++tot;
if(a[i]) addedge(s,na[i],a[i],0);
}
for(int i=1;i<=n;i++)
{
nb[i]=++tot;
if(b[i]) addedge(nb[i],t,b[i],0);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(a[i]&&b[j])
addedge(na[i],nb[j],inf,c[i][j]);
}
void flow()
{
int f=0;
while(spfa())
{
vis[t]=1;
memcpy(h,in,sizeof(in));
while(vis[t])
{
memset(vis,0,sizeof(vis));
f+=dfs(s,inf);
}
if(f==all) break;
}
printf("%d\n",ans<0?-ans:ans);
}
void clear()
{
cnt=1;ans=tot=0;
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
}
int main()
{
int n,m,i,j;
scanf("%d%d",&m,&n);
for(i=1;i<=m;i++)
scanf("%d",&a[i]),all+=a[i];
for(i=1;i<=n;i++)
scanf("%d",&b[i]);
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf("%d",&c[i][j]);
link(m,n);
flow();
clear();
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
c[i][j]=-c[i][j];
link(m,n);
flow();
return 0;
}