对于已经增广后的图,会出现一些反向边,首先跑一边最大流,只有对于被增广的路才有可能成为答案,考虑每一条被曾广的路,如果他在残留网络中两个端点在同一个强连通分量里,必然有其他的路径可以代替这条边,比如图中1 2 3 4 构成一个环3-》2-》1-》4-》3,3-》2可以替代原来的1》2,所以只有那些被增广后,起点终点不在一个强连通分量里,才对答案有贡献
#include
#include
#include
#include
#define N 100005
using namespace std;
int n,m,cnt=0,k=0;
struct edge
{
int to,ne,w;
}b[N*4];
int head[N];
bool v[N*2];
void add(int u,int v,int w)
{
b[k].to=v;b[k].ne=head[u];b[k].w=w;head[u]=k;
k++;
}
int dfn[N],low[N],ti=0,s[N],num=0,be[N],he=0;
bool vis[N];
void read()
{
int x,y;
scanf("%d%d",&n,&m);
cnt=n+1;
for(int i=1;i<=n/2;i++){
add(0,i,1); add(i,0,0);
}
for(int i=n/2+1;i<=n;i++){
add(i,cnt,1); add(cnt,i,0);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y,1); add(y,x,0);
}
}
int d[N];
bool bfs()
{
memset(d,0,sizeof(d));
queue q;
q.push(0);d[0]=1;
while(!q.empty())
{
int z=q.front();q.pop();
for(int i=head[z];i!=-1;i=b[i].ne)
if(b[i].w&&!d[b[i].to])
{
d[b[i].to]=d[z]+1;
q.push(b[i].to);
if(b[i].to==cnt) return 1;
}
}
return 0;
}
int dfs(int now,int f)
{
if(now==cnt) return f;
int tmp=f,k;
for(int i=head[now];i!=-1;i=b[i].ne)
if(b[i].w&&tmp&&d[b[i].to]==d[now]+1){
k=dfs(b[i].to,min(b[i].w,tmp));
if(!k) {d[b[i].to]=0;continue;}
b[i].w-=k;b[i^1].w+=k;tmp-=k;
}
return f-tmp;
}
void Targan(int x)
{
dfn[x]=low[x]=++ti;
vis[x]=1; s[++he]=x;
for(int i=head[x];i!=-1;i=b[i].ne)
if(b[i].w){
int to=b[i].to;
if(dfn[to]==-1){
Targan(to);
low[x]=min(low[x],low[to]);
}
else if(vis[to]==1) low[x]=min(low[x],dfn[to]);
}
int z;
if(dfn[x]==low[x]){
num++;
while(1){
z=s[he--];
be[z]=num;
vis[z]=0;
if(z==x) break;
}
}
}
int ans=0;
void judge()
{
for(int i=1;i<=n;i++)
if(dfn[i]==-1){
Targan(i);
}
for(int i=1;i<=n/2;i++)
for(int j=head[i];j!=-1;j=b[j].ne)
if(b[j].to>i&&b[j].to!=cnt&&b[j].w==0&&be[i]==be[b[j].to]) ans--;
}
int main()
{
// freopen("in.txt","r",stdin);
freopen("bloodsail.in","r",stdin);
freopen("bloodsail.out","w",stdout);
memset(head,-1,sizeof(head));
memset(dfn,-1,sizeof(dfn));
read();
while(bfs()==1) ans+=dfs(0,0x7fffffff);
judge();
printf("%d",ans);
// while(1);
return 0;
}