题目描述
小sun最近为了应付考试,正在复习图论,他现在学到了图的遍历,觉得太简单了,于是他想到了一个更加复杂的问题:
无向图有n个点,从点1开始遍历,但是规定:按照每次“走两步”的方式来遍历整个图。可以发现按照每次走两步的方法,不一定能够遍历整个图,所以现在小sun想问你,最少加几条边,可以完整的遍历整个图。
输入描述:
第一行两个整数n,m代表图的点数和边数。
接下来m行,每行两个整数u,v代表u,v有边相连(无向边)输出描述:
输出一行,代表最少要添加的边数。
题解
保证整个图肯定是需要联通的,那么我们需要求出有多少个连通块,需要加的边数就是连通块个数-1。
如果图联通,只要存在奇数环,那么就可以走完整个图,因为奇数环,从环的起点走到环的终点后,从终点继续走另一边到起点,这样之前遍历的是奇数点,第二次过来就变成了偶数点。其实就是判断这个图是不是二分图,用染色法即可。如果没有奇数环,只需要在其中一个连通块中,加上一条边形成奇数环即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
vector<int> v[N];//图的表示
int n,m,color[N],f;
void dfs(int x,int c){
color[x]=c;//顶点x染成c
for (int i = 0; i < v[x].size(); ++i){
if(color[v[x][i]]==c)f=0;
else if(!color[v[x][i]])dfs(v[x][i],-c);
}
}
void solve(){
//如果是连通图,则一次dfs即可访问所有位置
int k=0,num=0;
for (int i = 1; i <= n; ++i){
if (color[i]==0){
f=1;
dfs(i,1);
if(!f)k=1;
num++;
}
}
if(k)cout<<num-1;
else cout<<num;
}
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int x,y;cin>>x>>y;
v[x].push_back(y),v[y].push_back(x);
}
solve();
return 0;
}