F 题 方程不好直接解 二分求答案 (有单调性)
D 题 数据太少 而且是静态的 直接先暴力所有的 输入完一个一个对就好

E 题

链接:https://ac.nowcoder.com/acm/contest/1085/E
来源:牛客网

题目描述
小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.

如果不存在奇数环,那么可以将奇数个连通块连在一起构成一个奇数环,再与其它连通块连接,答案为连通块个数。

怎么求有多少个连通块,是否存在奇数环,可以用图染色的方法,如果存在奇数环,那么就存在相邻两个节点颜色一样,如果是偶数环,就不存在相邻两个节点颜色一样。

作者:sd197555
链接:https://ac.nowcoder.com/discuss/258571?type=101&order=time&pos=&page=1
来源:牛客网
考察这个遍历的性质,发现如果图存在奇环,那么跟当前奇环联通的所有点全部可以遍历到。
首先讨论图有多少个联通块,在这些联通块中,若存在一个包含奇环的联通块,那么将当前的联通块与所有的不包含奇环的联通块相连就行了,答案个数为不包含奇环的联通块个数。
若所有的联通块都不包含奇环,那么可以用若干条边在k个(k为奇数)联通块之间构造一条奇环,然后再把其他的联通块跟当前的奇环相连,答案为联通块的个数。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
int n, m, k;
int cas;

int head[maxn], cnt;
int to[maxn << 1], nxt[maxn << 1];

void ade(int a, int b) {
	to[++ cnt] = b;
	nxt[cnt] = head[a], head[a] = cnt;
}

int dfn[maxn], ans = 0;
bool v[maxn];
void dfs(int u, int f, int yuan) {
	dfn[u] = f;
	for(int i = head[u]; i; i = nxt[i]) {
		if(!dfn[to[i]]) dfs(to[i], f <= 1 ? 2 : 1, yuan);
		else if(f == dfn[to[i]]) {
			if(v[yuan]) continue;
			else ans ++;
			v[yuan] = 1;	
		}
	}
}

signed main() {
	scanf("%d %d", &n, &m);
	for(int i = 1, a, b; i <= m; i ++) {
		scanf("%d %d", &a, &b);
		ade(a, b), ade(b, a);
	}
	int coun = 0;
	for(int i = 1; i <= n;  i++) {
		if(!dfn[i]) {
			dfs(i, 0, i);
			coun ++;
		}
	}
	if(ans) cout << coun - ans << endl;
	else cout << coun << endl;
	return 0;
}