HDU - 5215

题目链接:HDU - 5215


对于奇环来说,直接二分图染色即可。

对于偶环来说,我们先DCC缩点。然后对于一个DCC来说,如果点数为偶数那么必然存在一个偶环。如果点数为奇数,如果边数不为点数,那么证明有多个环嵌套,如果是两个奇环那么一定可以抵消成偶环。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=1e5+10,M=N*6;
int n,m,low[N],dfn[N],dcc[N],num[N],sum[N],vis[N],mark[M],col[N],res[2],co,cnt;
int head[N],nex[M],to[M],tot; stack<int> s;
inline void add(int a,int b){to[++tot]=b; nex[tot]=head[a]; head[a]=tot;}
void dfs(int x,int co){
	col[x]=co;
	for(int i=head[x];i;i=nex[i]){
		if(col[to[i]]==-1)	dfs(to[i],co^1);
		else if(co==col[to[i]]) res[1]=1;
	}
}
void Tarjan(int x){
	low[x]=dfn[x]=++cnt; s.push(x); vis[x]=1;
	for(int i=head[x];i;i=nex[i])	if(!mark[i]){
		mark[i]=mark[i^1]=1;
		if(!dfn[to[i]]) Tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
		else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
	}
	if(low[x]==dfn[x]){
		int u; co++;
		do{
			u=s.top(); s.pop(); vis[u]=0; dcc[u]=co; num[co]++;
		}while(u!=x);
	}
}
void solve(){
	cin>>n>>m; tot=1; cnt=res[0]=res[1]=co=0;
	memset(low,0,sizeof low),memset(dfn,0,sizeof dfn),memset(mark,0,sizeof mark);
	memset(col,-1,sizeof col),memset(num,0,sizeof num),memset(head,0,sizeof head);
	memset(sum,0,sizeof sum);
	for(int i=1,a,b;i<=m;i++) scanf("%d %d",&a,&b),add(a,b),add(b,a);
	for(int i=1;i<=n;i++)	if(col[i]==-1)	dfs(i,0);
	for(int i=1;i<=n;i++)	if(!dfn[i])	Tarjan(i);
	for(int i=1;i<=n;i++)	for(int j=head[i];j;j=nex[j])
		if(dcc[i]==dcc[to[j]])	sum[dcc[i]]++;
	for(int i=1;i<=co;i++)	if(!(num[i]%2&&num[i]>=sum[i]/2))	res[0]=1;
	puts(res[1]?"YES":"NO");
	puts(res[0]?"YES":"NO");
}
signed main(){
	int T; cin>>T; while(T--) solve();
	return 0;
}

你可能感兴趣的:(HDU,双连通分量,图论)