二分图的定义及判定(Catch HDU - 3478)

二分图的定义

节点由两个集合组成,且两个集合内部没有边的图。
在这里插入图片描述

二分图的判定

由二分图的定义可知,二分图有着这样一个性质:
二分图不存在长度为奇数的环。
因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合。

这条性质将被用来判定一个无向图是否是二分图。
我们通常使用染色法判定二分图,将每个顶点染色,并且相邻的顶点染不同颜色,如果存在俩相邻点染上了同一颜色,则与二分图定义不符。

例题 Catch HDU - 3478

A thief is running away!
We can consider the city where he locates as an undirected graph in which nodes stand for crosses and edges stand for streets. The crosses are labeled from 0 to N–1.
The tricky thief starts his escaping from cross S. Each moment he moves to an adjacent cross. More exactly, assume he is at cross u at the moment t. He may appear at cross v at moment t + 1 if and only if there is a street between cross u and cross v. Notice that he may not stay at the same cross in two consecutive moment.
The cops want to know if there’s some moment at which it’s possible for the thief to appear at any cross in the city.

Input

The input contains multiple test cases:
In the first line of the input there’s an integer T which is the number of test cases. Then the description of T test cases will be given.
For any test case, the first line contains three integers N (≤ 100 000), M (≤ 500 000), and S. N is the number of crosses. M is the number of streets and S is the index of the cross where the thief starts his escaping.
For the next M lines, there will be 2 integers u and v in each line (0 ≤ u, v < N). It means there’s an undirected street between cross u and cross v.

Output

For each test case, output one line to tell if there’s a moment that it’s possible for the thief to appear at any cross. Look at the sample output for output format.

Sample Input

2
3 3 0
0 1
0 2
1 2
2 1 0
0 1

Sample Output

Case 1: YES
Case 2: NO

大意:给定一个n个点,m条边的无向图,再给定一个起点,单位时间内只能从一个边移动到相邻的点上,问可不可能存在一个时刻,小偷可能出现在地图上的任意位置。

思路:
1.如果这个图不连通,那么这个时刻将不存在。因为如果不连通,总会有到达不了的点。(并查集)
2.如果这个图是二分图,那么这个时刻将不存在。因为如果是二分图,定会将图分为俩个集合,一个集合是奇数时刻到达,一个集合是偶数时刻到达。(二分图判定)

在此附上我的AC代码

#include<iostream>
using namespace std;

int t;
int n, m, s, cnt;
int head[100005];
int color[100005];
int fa[100005];

int find(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}

void merge(int x, int y)
{
	if(find(x) == find(y)) return;
	fa[find(x)] = fa[find(y)];
}

bool judgetong()
{
	int a=fa[0], flag=1;
	for(int i=1;i<n;i++)
	{
		if(fa[i] != a){
			flag=0;
			break;
		}
	}
	if(flag) return true;
	return false;
}

void init()
{
	cnt = 0; 
	for(int i=0;i<n;i++) 
	{
		fa[i] = i;
		head[i] = -1;
		color[i] = 0; 
	}
}

struct node{
	int v;
	int next;
}bian[1000005];

void add(int u, int v)
{
	bian[cnt].v = v;
	bian[cnt].next = head[u];
	head[u] = cnt++;
}

bool bipartite(int u){
	for(int i=head[u];i!=-1;i=bian[i].next)
	{
		int v=bian[i].v;
		if(color[u] == color[v]) return false;
		if(!color[v]) 
		{
			color[v] = 3-color[u];
			if(!bipartite(v)) return false;
		}
	}
	return true;
}

int main()
{
	scanf("%d", &t);
	for(int q=1;q<=t;q++)
	{	
		scanf("%d%d%d", &n, &m, &s);
		init();
		int u, v;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d", &u, &v);
			add(u,v);
			add(v,u);
			merge(u,v);
		}
		for(int i=0;i<n;i++) find(i);
		if(!judgetong()) printf("Case %d: NO\n", q);
		else{
			color[0] = 1;
			if(!bipartite(0)) printf("Case %d: YES\n", q);
			else printf("Case %d: NO\n", q);
		}
	}
	return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值