题目大意:给出n和m,表示有n个城市和m张票,现在要进行一场旅行,要求将所有的票使用掉,问还需要自己买几张票。
解题思路:欧拉道路的题目,只要输入中出现的城市才需要去考虑它的度数,并且要考虑说两个图是否联通。
我的做法是,读入数据的时候,标记出现过的点,并且记录每个点的度数,并查集记录点属于哪一个集合。
然后首先保证每个子的联通图为欧拉通路(度数为奇数的点不超过2),然后在加上集合个数 - 1.
#include <stdio.h>
#include <string.h>
const int N = 100005;
int n, m, f[N], d[N], vis[N];
int cnt, rec[N], g[N];
int getfar(int x) {
int p, q, t;
p = q = x;
while (p != f[p]) p = f[p];
while (q != f[q]) {
t = q;
q = f[q];
f[q] = p;
}
return p;
}
void init() {
memset(d, 0, sizeof(d));
memset(g, 0, sizeof(g));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++) f[i] = i;
scanf("%d%d", &n, &m);
int a, b;
for (int i = 0; i < m; i++) {
scanf("%d%d", &a, &b);
vis[a] = vis[b] = 1;
d[a]++, d[b]++;
int x = getfar(a), y = getfar(b);
if (x != y) f[y] = x;
}
}
void handle() {
cnt = 0;
for (int i = 1; i <= n; i++) {
if (vis[i]) {
int x = getfar(i);
if (vis[x] != 2) rec[cnt++] = x;
if (d[i] & 1) g[x]++;
vis[x] = 2;
}
}
}
int solve() {
int ans = cnt - 1;
for (int i = 0; i < cnt; i++)
if (g[rec[i]] > 2) ans = ans + g[rec[i]] / 2 - 1;
return ans;
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
init();
handle();
printf("%d\n", solve());
}
return 0;
}