1. 程式人生 > >POJ2492_帶權並查集(註釋很詳細)

POJ2492_帶權並查集(註釋很詳細)

/*
題目大意:有一個教授正在研究一種昆蟲,他認為這種昆蟲之中沒有同性戀。
有n只這種昆蟲,他們之間有k個關係(不知道他們是什麼性別)
這k個關係大概是a與b交往(教授認為只有異性可以交往)
問給的這組資料能否支援教授的觀點

解題思路:可以用帶權並查集來求解
開我們假設,交往的都是異性,
比如a b交往
同時b c交往
這是我們可以推得a c為同性
如果輸入這時候有a c那麼說明這時候出現的同性戀(既a b,b c,a c中有一組同性戀)
這時直接輸出無法支援教授的觀點

所以問題的關鍵變成了:我們如何將已有輸入的關係進行合理的構建,並對當前的輸入進行判斷的問題(通過判斷來尋找矛盾)
在剛才的例子中
比如a b交往
同時b c交往
我們只要知道a的性別既可以知道b和c的性別
所以我們只要將所有有關係的蟲子的id通過指標連在一起同時記錄這個蟲子和她連的上一個蟲子的性別關係0表示同性,1表示異性
於是當出現a b有交往就變成了一下兩部
首先檢查a b是否已經有關係,及是否已經在同一個帶權並查集中了,如果兩個的root一樣,那麼它兩個的關係是已知的了,於是可以通過都想上找跟,看他兩跟跟的關係
如果一個是0 一個是1那麼就可以,如果兩個都是1或是0就不行

如果兩個原先沒有關係,既原先的兩條鏈是不相連的,沒有公工的root,就將兩個連在一起


pe了一次,因為每次輸出結尾要加一個空行
*/
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 2e3 + 7; int Pre[maxn];//用於儲存並查集的指標,Pre[i]表示與i有關係的上一位 int Rela[maxn];//Rela[i]表示i與上一位的關係 int findroot(int x, int &r)//尋找x的跟,同時處理x和跟的關係 { r = 0; while (x != Pre[x]) { r = (r + Rela[x]) % 2
; x = Pre[x]; } return x; } int main() { int T; cin >> T; for (int c = 1; c <= T; c++) { for (int i = 0; i<maxn; i++) { Pre[i] = i;//自己就是root Rela[i] = 0;//沒有上一位,定義為和自己同性吧 } printf("Scenario #%d:\n", c); int
n, k; cin >> n >> k; int x, y; bool flag = true;//假設教授的觀點是真的 for (int i = 0; i<k; i++) { scanf("%d%d", &x, &y); if (!flag) { continue; } int r0, r1; int ro0 = findroot(x, r0); int ro1 = findroot(y, r1); if (ro0 != ro1)//兩者之間的關係目前還不知道,建立關係 { Pre[ro1] = ro0;//將ro1的那條連只想ro0 //重新設定Rela[ro1] Rela[ro1] = (r1 - r0 - 1 + 2) % 2; } else//已經知道兩者之間的關係,只要檢查就行了 { if (r0 == r1) { flag = false; } } } if (!flag) { cout << "Suspicious bugs found!" << endl; } else { cout << "No suspicious bugs found!" << endl; } cout << endl; } return 0; }

還剩994道,加油!!!