1. 程式人生 > 實用技巧 >Ant Trip 題解

Ant Trip 題解

Ant Trip

分析

題意很簡單,爆搜的時間複雜度比較高,不考慮。
應該使用歐拉回路的相關知識求解。

intn()

輸入時將兩個節點的入度都加一(無向),然後將兩個節點合併在一個連通圖中.

for (int i = 1, u, v; i <= m; i++) {
      scanf ("%d %d", &u, &v);
      in[v] ++, in[u] ++;
      UnionSet(u, v);
}

work()

step1

從1~n迴圈,依次列舉,記錄每個連通圖中的點數。
用一個ans[]陣列儲存連通圖中度為奇數的節點。

step2

再列舉一遍
如果一個連通圖中的節點數不大於1,就不用畫,跳過。
如果ans[]為0,這次圖是一個歐拉回路,就sum++
如果ans[]不為零 sum += ans[]/2
因為一筆只能夠畫掉兩個奇數度數的節點(因為TFW不停問,特此強調),所以只加上ans[]/2

程式碼

#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];
/* num -> 儲存一個連通塊裡有幾個節點*/

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;
}