【Ant Trip】題解
阿新 • • 發佈:2020-08-20
題目描述
給你無向圖的n個點和m條邊,保證這m條邊都不同且不會存在同一點的自環邊,現在問你至少要幾筆才能所有邊都畫一遍。(一筆畫的時候筆不離開紙)
輸入格式
多組資料,每組資料用空行隔開。
對於每組資料,第一行兩個整數n, m表示點數和邊數。接下去m行每行兩個整數a, b,表示a, b之間有一條邊。
輸出格式
對於每組資料,輸出答案。
樣例輸入
3 3
1 2
2 3
1 3
4 2
1 2
3 4
樣例輸出
1
2
分析
做這道題,首先我們需要知道這些:
- 若一張圖只有一個點,那麼一筆都不需要畫
- 假如他是一個半尤拉圖,那麼也只需要一筆
- 以上兩種都不是的話,那麼我們需要畫的筆數應該等於這張圖中度為奇數的點數之和除以 2
那麼我們怎麼判斷是否為一個尤拉圖呢?暴搜?記得雷老師說過,假如一張圖是尤拉圖,那麼他的所有點的度應該都是偶數。
其實這道題的題目並沒有說所給出的資料是一張連通圖,所以我們又可以用一個並查集來求出每一個聯通分量,並用一個數組來儲存這個聯通分量之中的度為奇數的點的個數(好像有點囉嗦)
看懂了的話,可以自己實現一遍,發現有問題再看程式碼吧~
程式碼
#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1e5 * 2 + 5; int fa[MAXN]; int in[MAXN]; int num[MAXN]; int ans[MAXN]; int Find (int x) { if (fa[x] != x) fa[x] = Find (fa[x]); return fa[x]; }//找爸爸 int main() { int n, m; while ((scanf("%d %d", &n, &m)) != EOF) { for (int i = 1; i <= n; i++) fa[i] = i; memset (num, 0, sizeof num); memset (ans, 0, sizeof ans); memset (in, 0, sizeof in);//每次都要初始化陣列(錯了好幾次,害) for (int i = 1; i <= m; i++) { int x, y; scanf("%d %d", &x, &y); in[x] ++; in[y] ++;//度累加 x = Find (x); y = Find (y); if (x != y) fa[x] = y; //假如他們不在一個聯通分量之中,就把他們放進同一個 } for (int i = 1; i <= n; i++) { int x = Find (i); // i 的祖先。因為我們在之前是做了一個並查集的,假如說他們在一個連通分量之中,那麼他們的祖先就應該是相同的 num[x] ++;//這個聯通分量中的點數累加 if (in[i] % 2 == 1) ans[x] ++;//因為我們已經知道 i 是這個聯通分量中的值了,所以在這裡用 ans 陣列來累加他所在的連通分量的度為奇數的點的個數 //此處其實就是用祖先來作為下標方便儲存,其實也可以在上面輸入時合併 x 和 y 的時候就用一個 vector 陣列來儲存以 x 為祖先的一個集合,最後看那些集合是有數的,就做一遍下面的操作,請自己實現! } int sum_ = 0;//用於累加答案 for (int i = 1; i <= n; i++) { if (num[i] <= 1) continue;//假如只有 1 個點,就不用管(0 個更不用) if (ans[i] == 0) sum_ ++;//假如這個連通分量之中所有點的度都沒有奇數,說明有尤拉路,一筆畫成 else sum_ += ans[i] / 2;//以上兩種都不是的話,那麼我們需要畫的筆數應該等於這張圖中度為奇數的點數之和除以 2 } printf("%d\n", sum_);//完美結束 } return 0; }