最小割定理:
最小割的必须边
一定在最小割中的边、扩大容量后能增大最大流的边, ① 满流;② 残余网络中S能到入点、出
点能到T。 从S开始DFS、T开始反向DFS,标记到达的点,然后枚举满流边即可。
最小割的可行边
被某一种最小割的方案包含的边, ① 满流;② 删掉之后在残余网络中找不到u到v的路
径。 在残余网络中tarjan求SCC,(u,v)两点在同一SCC中说明残余网络中存在u到v路径。
知道结论后就好做了。
首先S向小于n/2,小于n/2向大于n/2,大于n/2向T建容量为1的边,跑出最大匹配。
然后在网络残图中跑tarjan,如果最大流中的一条边起点和终点不在同一个强连通分量。
那么砍掉这条边就是合法的,如果起点和终点在同一个强连通分量,那么ans--。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define inf 100000000
using namespace std;
struct bian
{
int qi,zhong,w,next;
};
bian c[1000000];
int n,m,jishu=0,hd,tl,x,y,xuan,ying,jishu3=0,jishu2=0,ji=0;
int head[200000],dep[200000],q[200000],belong[200000],dfn[200000],low[200000],zhan[200000];
bool chu[200000],ru[200000],in[200000];
void add(int x,int y,int z)
{
c[jishu].qi=x;
c[jishu].zhong=y;
c[jishu].w=z;
c[jishu].next=head[x];
head[x]=jishu++;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
hd=tl=0;
q[++tl]=xuan;
dep[xuan]=1;
while(hd<tl)
{
int op=q[++hd];
for(int i=head[op];i!=-1;i=c[i].next)
{
if(c[i].w&&(!dep[c[i].zhong]))
{
dep[c[i].zhong]=dep[op]+1;
q[++tl]=c[i].zhong;
if(c[i].zhong==ying)
return 1;
}
}
}
return 0;
}
int dfs(int op,int fw)
{
if(op==ying) return fw;
int tmp=fw,k;
for(int i=head[op];i!=-1;i=c[i].next)
{
if(c[i].w&&tmp&&dep[c[i].zhong]==dep[op]+1)
{
k=dfs(c[i].zhong,min(c[i].w,tmp));
if(!k)
{
dep[c[i].zhong]=0;
continue;
}
c[i].w-=k;
c[i^1].w+=k;
tmp-=k;
}
}
return fw-tmp;
}
void tarjan(int x)
{
low[x]=++jishu2;
dfn[x]=jishu2;
zhan[++jishu3]=x;
in[x]=1;
for(int i=head[x];i!=-1;i=c[i].next)
{
if(!c[i].w) continue;
if(dfn[c[i].zhong]==-1)
{
tarjan(c[i].zhong);
low[x]=min(low[x],low[c[i].zhong]);
}
else if(in[c[i].zhong])
low[x]=min(low[x],dfn[c[i].zhong]);
}
if(dfn[x]==low[x])
{
int y;
ji++;
while(1)
{
y=zhan[jishu3--];
in[y]=0;
belong[y]=ji;
if(y==x)
break;
}
}
}
int main()
{
freopen("bloodsail.in","r",stdin);
freopen("bloodsail.out","w",stdout);
memset(head,-1,sizeof(head));
memset(dfn,-1,sizeof(dfn));
scanf("%d%d",&n,&m);
xuan=0;ying=n+1;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
if(!chu[x])
{
add(xuan,x,1);
add(x,xuan,0);
chu[x]=1;
}
if(!ru[y])
{
add(y,ying,1);
add(ying,y,0);
ru[y]=1;
}
add(x,y,1);
add(y,x,0);
}
int shu=0;
while(bfs())
shu+=dfs(0,inf);
for(int i=1;i<=n;++i)
if(dfn[i]==-1)
tarjan(i);
for(int i=1;i<=n/2;++i)
for(int j=head[i];j!=-1;j=c[j].next)
if(c[j].w==0&&c[j].zhong!=0&&belong[c[j].qi]==belong[c[j].zhong])
shu--;
printf("%d",shu);
return 0;
}