清理雪道
题目描述:http://www.lydsy.com/JudgeOnline/problem.php?id=2502
题解
get写最小流的正确姿势。
按照可行流建图,然后先不连T到S流量为的inf边。
跑一遍最大流。
再加上那条边,再跑一遍最大流。
后一次跑的答案就是最小流。
原理,大概是前一次先把流量尽力拓展完,后一次再补下界(口胡的)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define inf 1050000000
#define N 110
#define M 50000
using namespace std;
int n,m,ans,S,T,ss,tt,d[N];
int k=1,la[N],ff[M],q[N],dep[N];
struct node{int a,b,c;}map[M];
void add(int a,int b,int c)
{
map[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;
map[++k]=(node){b,a,0};ff[k]=la[b];la[b]=k;
}
int dfs(int x,int flow)
{
if(x==tt)return flow;
int res=0,tmp;
for(int a=la[x];a&&flow;a=ff[a])
if(dep[map[a].b]==dep[x]+1&&map[a].c)
{
tmp=dfs(map[a].b,min(flow,map[a].c));
map[a].c-=tmp;map[a^1].c+=tmp;res+=tmp;flow-=tmp;
}
if(!res)dep[x]=-1;
return res;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
int l=1,r=2;q[1]=ss;dep[ss]=1;
while(l<r)
{
int x=q[l];l++;
for(int a=la[x];a;a=ff[a])
if(!dep[map[a].b]&&map[a].c)
q[r]=map[a].b,dep[q[r]]=dep[x]+1,r++;
}
return dep[tt];
}
int main()
{
int x;
scanf("%d",&n);
S=n+1;T=S+1;ss=T+1;tt=ss+1;
for(int i=1;i<=n;i++)
{
scanf("%d",&m);
for(int j=1;j<=m;j++)
scanf("%d",&x),add(i,x,inf),d[i]--,d[x]++;
}
for(int i=1;i<=n;i++)
{
if(d[i]>0)add(ss,i,d[i]);
if(d[i]<0)add(i,tt,-d[i]);
add(S,i,inf);add(i,T,inf);
}
while(bfs())dfs(ss,inf);add(T,S,inf);
while(bfs())ans+=dfs(ss,inf);
printf("%d\n",ans);
return 0;
}