时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小sun最近为了应付考试,正在复习图论,他现在学到了图的遍历,觉得太简单了,于是他想到了一个更加复杂的问题:
无向图有n个点,从点1开始遍历,但是规定:按照每次“走两步”的方式来遍历整个图。可以发现按照每次走两步的方法,不一定能够遍历整个图,所以现在小sun想问你,最少加几条边,可以完整的遍历整个图。
输入描述:
第一行两个整数n,m代表图的点数和边数。
接下来m行,每行两个整数u,v代表u,v有边相连(无向边)
输出描述:
输出一行,代表最少要添加的边数。
示例1
输入
5 4
1 2
2 3
3 4
4 5
输出
1
示例2
输入
5 5
1 2
2 3
3 4
4 5
1 5
输出
0
备注:
数据范围:
3≤n≤1e5, 2≤m≤1e5
1≤u,v≤n
图中点的编号从1到n。
走两步的意思:
比如现在有两条边:(1,2),(2,3),从1开始走,只能走到1或者3。
(1->2->3),(1->2->1)
题解
首先,所有点都能到达,也就是图要连通,不连通的话走都走不到肯定不行,所以加边来连通它们。加边数就是现在存在的连通块的数量-1
都连通之后,每次两步两步的走,所走到的点都是偶数点,而奇数点无法走到,所以我们需要构造一个环,使得可以通过环从偶数点迈到奇数点,然后走的就全是奇数点了,这样全部都走完
注意,所连成的环如果是偶环,通过环走到的还是偶数,所以要构成奇环,把一个单独隔开剩下的不就成奇数了
总结下,答案就是连通块的个数+(0/1)
如果存在奇数环就加0,如果没有需要我们现构造,就加1
!((vis[v] - vis[u]) & 1)flag=0;
如果vis[v]-vis[u]的结果ans是偶数,ans&1就是0,!0=1,所以flag=0,也就是v到u的距离是偶数,再加上一个u到v的边就构成奇环,所以不用加一,表示flag=0
代码:
#include<bits/stdc++.h>
#include<bitset>
using namespace std;
typedef long long ll;
const int maxn = 100007;
struct node {
int v,next;
}edge[maxn*2];
int head[maxn],cnt;
bool flag = 1;
int vis[maxn];
void add(int u,int v) {
edge[++cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void dfs(int u,int fa) {
vis[u] = vis[fa] + 1;
for(int i = head[u];i;i = edge[i].next)
{
int v ;
v= edge[i].v;
if(v == fa) continue;
if(vis[v])
{
if(!((vis[v] - vis[u]) & 1) ) flag = 0;
continue;
}
dfs(v,u);
}
return;
}
int main() {
int n,m,ans = 0;
cin>>n>>m;
for(int i = 1;i <= m;++i)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i = 1;i <= n;++i)
{
if(vis[i]) continue;
ans++;
dfs(i,0);
}
cout<<ans - 1 + flag;
return 0;
}