HDU 3478 Catch (连通性&&二分图判断)

链接

[https://vjudge.net/contest/281085#problem/C]

题意

一个n个点,m条边的图,开始的点是s
每次必须移动到相邻的位置,问你是否存在某个时刻所有点都可能到达

分析

图的话用邻接表vectorc存,这个非常实用
首先,如果一个图不是联通的话就不可能存在
其次,如果一个图是二分图的话就不可能存在,因为二分图某一时刻只能在两个点集之一
画图就知道了,其他绝对是可以的,自己画图就会发现了,我也是看了别人的才知道这个套路
经验收获啊!
1.并查集判断是否联通
2.二分图染色,每次把相邻的染为相反颜色,判断是否有矛盾(相邻两个点颜色相同)。

代码

#include<iostream>
#include<string.h>
#include<cstdio>
#include<vector>
using namespace std;
const int N=1e5+10;
int t,n,m,s;
int f[N],col[N];
vector<int> ve[N];
int find(int x){
	if(f[x]==-1)
	return x;
	return f[x]=find(f[x]);
}
bool ok(int u){
	for(int i=0;i<ve[u].size();i++){
		int v=ve[u][i];
		if(col[u]==col[v]) return false;
		if(col[v]==0){
			col[v]=3-col[u];
			if(!ok(v)) return false;
		}
	}
	return true;
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%d",&t);
	int kase=0;
	while(t--){
		scanf("%d%d%d",&n,&m,&s);
		for(int i=0;i<n;i++)
			ve[i].clear();
	   memset(col,0,sizeof(col));
	   memset(f,-1,sizeof(f));
		int a,b;
		for(int i=0;i<m;i++){
			scanf("%d%d",&a,&b);
			int f1=find(a);
			int f2=find(b);
			if(f1!=f2)
			f[f2]=f1;
			ve[a].push_back(b);
			ve[b].push_back(a);
		}
		int cnt=0;
		for(int i=0;i<n;i++)
		if(find(i)==i) cnt++;
		if(cnt>1){//不连通 
			printf("Case %d: NO\n",++kase);
			continue;
		}
		col[s]=1;
		bool flag=ok(s);
		if(flag){
			printf("Case %d: NO\n",++kase);
		}
		else printf("Case %d: YES\n",++kase);
	}
	return 0;
}
posted @ 2019-01-26 20:06  ChunhaoMo  阅读(218)  评论(0编辑  收藏  举报