分析
题意很简单,爆搜的时间复杂度比较高,不考虑。
应该使用欧拉回路的相关知识求解。
intn()
输入时将两个节点的入度都加一(无向),然后将两个节点合并在一个连通图中.
1 2 3 4 5
| for (int i = 1, u, v; i <= m; i++) { scanf ("%d %d", &u, &v); in[v] ++, in[u] ++; UnionSet(u, v); }
|
TFW居然都不知道要将两个节点合并在一个连通图中
work()
step1
从1~n循环,依次枚举,记录每个连通图中的点数。
用一个ans[]数组保存连通图中度为奇数的节点。
step2
再枚举一遍
如果一个连通图中的节点数不大于1,就不用画,跳过。
如果ans[]为0,这次图是一个欧拉回路,就sum++
如果ans[]不为零 sum += ans[]/2 TFW只顾抄代码,连ans[]/2都不知道啥意思
因为一笔只能够画掉两个奇数度数的节点 (因为TFW不停问,特此强调) ,所以只加上ans[]/2
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <vector> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1e5 + 5;
int n, m, sum; int in[MAXN], num[MAXN], ans[MAXN], fa[MAXN];
int FindSet(int v) { if (fa[v] == v) return v; else return fa[v] = FindSet(fa[v]); }
void UnionSet(int u, int v) { int x = FindSet(u); int y = FindSet(v); if (x == y) return ; else fa[x] = y; }
int main() { while (scanf ("%d %d", &n, &m) != EOF) { sum = 0; for (int i = 1; i <= n; i++) { fa[i] = i; ans[i] = 0; num[i] = 0; in[i] = 0; } for (int i = 1, u, v; i <= m; i++) { scanf ("%d %d", &u, &v); in[v] ++, in[u] ++; UnionSet(u, v); } for (int i = 1; i <= n; i++) { num[FindSet(i)] ++; if (in[i] % 2 == 1) { ans[FindSet(i)] ++; } } for (int i = 1; i <= n; i++) { if (num[i] <= 1) continue; if (ans[i] == 0) sum ++; else { sum += ans[i] / 2; } } printf ("%d\n", sum); } return 0; }
|