[HAOI2017]新型城市化

Posted by Dispwnl on April 28, 2019

题目

题解

给定的是个二分图,发现题目就是给定一张图的反图,要求在反图中删掉哪条边能使原图最大团大小增加

因为有定理$原图最大团=反图最大独立集=点数-最大匹配数$,所以现在要求的就是删掉哪条边能使最大匹配数减少,即此边是必选边

首先这条边$(u,v)$的反边必须满流,而且在残量网络上$u$和$v$不在同一个强连通分量里

我的理解是如果在同一个强连通分量里,说明可以不选这条边(即把这条边反由向变正向),把相对的另一条原来是正向的边反向(表示有流量通过)来保持结果不变……差不多这个理吧应该是

代码

# include<iostream>
# include<cstring>
# include<vector>
# include<cstdio>
# include<algorithm>
# define X first
# define Y second
# define mp make_pair
# define Pi pair<int,int>
using namespace std;
const int MAX=3e5+5;
struct p{
	int x,y,d,id;
}c[MAX];
int n,m,num=1,Top,T,cnt,ans,tot;
int qu[MAX],dfn[MAX],st[MAX],col[MAX],low[MAX],d[MAX],h[MAX],H[MAX],ouo[MAX];
bool use[MAX];
vector<int> vec[MAX];
Pi _[MAX],__[MAX];
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
void add(int x,int y,int d,int id=0)
{
	c[++num]=(p){h[x],y,d},h[x]=num;
	c[++num]=(p){h[y],x,0,id},h[y]=num;
}
void Add(int x,int y) {vec[x].push_back(y),vec[y].push_back(x);}
void Bfs(int x)
{
	int hl=1,tl=1;
	qu[1]=x,ouo[x]=1;
	while(hl<=tl)
	{
		int tt=qu[hl++];
		for(int v:vec[tt])
		  if(!ouo[v]) ouo[v]=-ouo[tt],qu[++tl]=v;
	}
}
bool bfs()
{
	memset(d,0,sizeof(d));
	int hl=1,tl=d[0]=1;
	qu[1]=0;
	while(hl<=tl)
	{
		int tt=qu[hl++];
		for(int i=h[tt],y;i;i=c[i].x)
		  if(!d[y=c[i].y]&&c[i].d)
		  {
		  	d[y]=d[tt]+1,qu[++tl]=y;
		  	if(y==T) return 1;
		  }
	}
	return 0;
}
int dfs(int x=0,int dix=1e8)
{
	if(x==T||!dix) return dix;
	int sum=0;
	for(int &i=H[x],dis,y;i;i=c[i].x)
	  if(d[y=c[i].y]==d[x]+1&&c[i].d)
	  {
	  	dis=dfs(y,min(dix,c[i].d));
	  	if(dis)
	  	{
	  		c[i].d-=dis,c[i^1].d+=dis,sum+=dis,dix-=dis;
	  		if(!dix) break;
		}
	  }
	if(!sum) d[x]=-2;
	return sum;
}
void Dinic()
{
	int tot=0,D;
	while(bfs())
	{
		memcpy(H,h,sizeof(H));
		while(D=dfs()) tot+=D;
	}
}
void Tarjan(int x)
{
	low[x]=dfn[x]=++cnt,st[++Top]=x,use[x]=1;
	for(int i=h[x],y;i;i=c[i].x)
	  if(c[i].d) if(!dfn[y=c[i].y]) Tarjan(y),low[x]=min(low[x],low[y]);
	  else if(use[y]) low[x]=min(low[x],dfn[y]);
	if(low[x]==dfn[x])
	{
		int tt=-1;
		++ans;
		while(tt!=x) tt=st[Top--],use[tt]=0,col[tt]=ans;
	}
}
int main()
{
	n=read(),m=read(),T=n+1;
	for(int i=1,x,y;i<=m;++i)
	  {
	  	x=_[i].X=read(),y=_[i].Y=read();
	  	if(x>y) swap(_[i].X,_[i].Y);
	  	Add(x,y);
	  }
	for(int i=1;i<=n;++i)
	  {
	  	if(!ouo[i]) Bfs(i);
	  	if(ouo[i]==1) add(0,i,1);
	  	else add(i,T,1);
	  }
	for(int i=1;i<=m;++i)
	  if(ouo[_[i].X]>ouo[_[i].Y]) add(_[i].X,_[i].Y,1,i);
	  else add(_[i].Y,_[i].X,1,i);
	Dinic();
	for(int i=0;i<=T;++i)
	  if(!dfn[i]) Tarjan(i);
	for(int i=3;i<=num;i+=2)
	  if(!c[i].d) use[c[i].id]=1;
	for(int i=1;i<=m;++i)
	  if(!use[i]) if(col[_[i].X]!=col[_[i].Y]) __[++tot]=_[i];
	sort(__+1,__+1+tot),printf("%d\n",tot);
	for(int i=1;i<=tot;++i)
	  printf("%d %d\n",__[i].X,__[i].Y);
	return 0;
}