【金牌导航】【网络流初探】卖猪问题
题目
解题思路
难处理的地方在与猪圈开门后,里面的猪可以去到开着的其它开着的猪圈
可以理解为这几个猪圈合并成了个大的,能在里面任一猪圈卖猪
建立源点与各猪圈相连,流量为猪圈中猪的数量
然后猪圈和第一个打开ta的顾客相连,其余顾客连向打开ta的前一个顾客
每一个顾客都连向汇点,流量为购买量
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=1e9;
struct lzf{
int to,z,nxt;
}f[100010];
int n,m,x,y,s,z,t=1,ans,p[100010],d[100010],now[100010],head[100010];
void add(int x,int y,int c)
{
f[++t].to=y;
f[t].z=c;
f[t].nxt=head[x];
head[x]=t;
f[++t].to=x;
f[t].nxt=head[y];
head[y]=t;
}
bool bfs()
{
memset(d,0x7f,sizeof(d));
queue<int>q;
q.push(s);
d[s]=0,now[s]=head[s];
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=head[x];i;i=f[i].nxt)
if (f[i].z>0&&d[f[i].to]==d[0])
{
q.push(f[i].to);
now[f[i].to]=head[f[i].to];
d[f[i].to]=d[x]+1;
if (f[i].to==z) return true;;
}
}
return false;
}
int dfs(int x,int sum)
{
if (x==z) return sum;
int k,res=0;
for (int i=now[x];i&∑i=f[i].nxt)
{
now[x]=i;
if (d[f[i].to]==d[x]+1&&f[i].z>0)
{
k=dfs(f[i].to,min(sum,f[i].z));
if (!k) d[f[i].to]=inf;
f[i].z-=k;
f[i^1].z+=k;
res+=k;
sum-=k;
}
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
s=n+m+1,z=s+1;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
add(s,i,x); //猪圈连源点
}
for (int i=1;i<=m;i++)
{
scanf("%d",&x);
for (int j=1;j<=x;j++)
{
scanf("%d",&y);
if (!p[y]) add(y,i+n,inf); //第一个顾客连猪圈
else add(p[y],i+n,inf); //向前一个顾客连
p[y]=i+n;
}
scanf("%d",&x);
add(i+n,z,x);
}
while (bfs()) ans+=dfs(s,inf); //跑最大流
printf("%d",ans);
return 0;
}