1. 程式人生 > >luogu1330_封鎖陽光大學 圖的遍歷

luogu1330_封鎖陽光大學 圖的遍歷

傳送門

解釋:(轉自洛谷題解)

首先,肯定要明確一點,那就是這個圖是不一定聯通的。於是,我們就可以將整張圖切分成許多分開的連同子圖來處理。然而最重要的事情是:如何處理一個連通圖?

乍看下去,似乎無從下手,因為方案好像有很多種,根本就列舉不完。但是,關鍵要注意到題目中重要的兩個條件,我們把它抽象成這兩個要素:

①每一條邊所連線的點中,至少要有一個被選中。

②每一條邊所連線的兩個點,不能被同時選中。

由此,可以推斷出:每一條邊都有且僅有一個被它所連線的點被選中。

又因為我們要處理的是一個連通圖。所以,對於這一個圖的點的選法,可以考慮到相鄰的點染成不同的顏色。

於是,對於一個連通圖,要不就只有兩種選法(因為可以全部選染成一種色的,也可以全部選染成另一種色的),要不就是impossible!

所以,我們只需要找到每一個子連通圖,對它進行黑白染色,然後取兩種染色中的最小值,然後最後彙總,就可以了。

另外,要判斷impossible,只需要加一個used陣列,記錄已經遍歷了哪些點。如果重複遍歷一個點,且與上一次的顏色不同,則必然是impossible的。、

 

my code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define rep(i, a, b) for (int i = a; i <= b; ++i)
 5 
 6
const int N = 1e5 + 7; 7 8 int n, m, vis[N], cnt[3], ans; 9 10 bool used[N]; 11 12 vector<int> e[N]; 13 14 void dfs(int u, int col) { 15 if (!used[u]) { 16 used[u] = 1; 17 vis[u] = col; 18 cnt[col]++; 19 for (auto v : e[u]) { 20 dfs(v, 3 - col);
21 } 22 } 23 else if (col != vis[u]) { 24 puts("Impossible"); 25 exit(0); 26 } 27 } 28 29 int main() { 30 scanf("%d%d", &n, &m); 31 32 rep(i, 1, m) { 33 int u, v; 34 scanf("%d%d", &u, &v); 35 e[u].push_back(v); 36 e[v].push_back(u); 37 } 38 39 rep(i, 1, n) if (!used[i]) { 40 cnt[1] = cnt[2] = 0; 41 dfs(i, 1); 42 ans += min(cnt[1], cnt[2]); 43 } 44 45 printf("%d\n", ans); 46 47 return 0; 48 }