1. 程式人生 > >洛谷 P1330 封鎖陽光大學

洛谷 P1330 封鎖陽光大學

        很神奇的做法,之前沒有仔細思考,貪心+優先佇列去找儘可能連線多條邊的點,但其實是有問題的,這樣貪心的結果很可能是沒有解的,而選取其他的沒那麼多條邊的點去操作,反而是可能有解的,所以貪心不可取。

         看了大佬們的思路才理解到這個題可以這樣設計(思路借鑑的,已註明轉載),這個題可以分為若干個聯通圖,那麼我們發現,對於某一條邊來說,如果他連線的一個節點被選取了,那麼他的另一個節點一定是沒有被選取的,那麼利用這個思路,我們發現,對於一個聯通圖來說,我們隨意一個節點之後,剩下的節點的狀態一定是全部確定的,因為圖聯通,隨意一個點經過一條路徑一定可以到達聯通圖上的任意一個點,那麼這個圖就只有兩個狀態了,第一個是我們選取的那個節點被使用,和我們選取的那個節點不被使用,那麼兩種圖我們取其中最小的使用個數,然後對個聯通圖的結果求和就是我們所需要的答案。

因為關係是一層一層推進的,所以bfs寫法特別的方便,而且如果我們的下一層節點的使用情況已經標記,那麼需要判斷和當前我們的節點標記是否一致,如果一致說明這個方法會有一條邊兩個節點都選取了的情況,那麼輸出impossible即可。

程式碼如下:

#include <bits/stdc++.h> using namespace std; typedef long long LL; int gcd(int a,int b){if (b == 0) return a; return gcd(b , a%b);} int lcm(int a, int b){ return a/gcd(a,b)*b;} inline int read(){     int f = 1, x = 0;char ch = getchar();     while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}     while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}     return x * f; } const int maxn = 1e5 + 10; int vis[maxn]; vector<int> v[maxn]; queue<int> q,q1; int main(){     int n = read(),m = read(),sum = 0;     for (int i = 0; i < m; ++i) {         int a = read(), b = read();         v[a].push_back(b);         v[b].push_back(a);     }     for (int i = 1; i <= n; ++i) {         if (vis[i] == 0){             q.push(i);             vis[i] = 1;             int cnt1 = 0,cnt2 = 0;// 1 代表染色,-1代表不染色             while(!q.empty()) {                 int now = q.front(), tag = 1;                 q.pop();                 if (vis[now] == 1) cnt1++;                 else cnt2++;                 for (int i = 0; i < v[now].size(); ++i) {                     if (vis[v[now][i]] == vis[now]) {                         cout << "Impossible" << endl;                         return 0;                     }                     if (vis[v[now][i]] == 0) {                         q.push(v[now][i]);                         vis[v[now][i]] = -vis[now];                     }                 }             }             while (!q.empty()) q.pop();             sum += min(cnt1,cnt2);         }     }     cout << sum << endl;     return 0; }