图的遍历 二分图染色

传送门

题意:
给出无向图,从1开始遍历,每次走两步,问最少加几条边可以
完整遍历整个图。

分析:
首先要走完整个图,那么整个图需要是连通的。那么就先添加边
使整个图连通,需要添加的边数为:当前连通块个数-1;
然后,如果图是连通的了,因为每次要走两步,如果没有环,
那么怎么走过去就会怎么走回来,那么之前因为走两步跳过的点
无论如何都遍历不到。如果是偶环,还是遍历不到。
因此只有奇数个点的环才能这样过去,回来的时候遍历到之前恰好遍历
不到的点。
因此只需要判断奇环是否存在了。如果存在奇环,那么最终答案就是连通块数目-1.
如果不存在奇环,答案还要加上1(加一条边就能连出一个奇环)。

那么如何判断奇环呢?
那就是:相邻的点已被染色,并且颜色相同,说明有奇环。

具体:
G为二分图的充要条件是G中的每一个环的长度都是偶数 。
由于二分图中不能含有奇环,所以我们只需用染色法判断是否是二分图即可;

二分图是值可以将点集分成两半,每个集合内都没有边,但可以与另一个集合中的点构成边,当且仅当一个图不存在奇数环的时候是二分图,奇数环是指环中的边数为奇数,染色法:将一个图染成只有0和1两种颜色,dfs每一个点,连通的染成不同颜色,如果发现这两个点连通且颜色相同,则说明出现了奇数环,一定不是一个二分图。

考察:
图:染色,连通块,判断是否有奇环,二分图染色

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
vector<int> e[N];
int n,m,ans,v[N],flag=1;//flag=0时说明有奇环 

void dfs(int x){
	for(auto &it:e[x]){
		if(v[it]==-1){//没被染色 
			v[it]=v[x]^1;//相邻的点染相反的颜色
			dfs(it); //把x所在的连通块全部染色
		}
		else if(v[it]==v[x]) flag=0;//相邻的点已被染色,并且颜色相同,说明有奇环 
	}
} 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
	}
	memset(v,-1,sizeof(v));
	for(int i=1;i<=n;i++){
		if(v[i]==-1){
			ans++;
			v[i]=0;//进行染色
			dfs(i); 
		}
	}
	printf("%d\n",ans-1+flag);//ans为连通块个数,那么需要添加的边数为ans-1 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值