CodeVS-2597 團伙(並查集)
題目:CodeVS-2597
題目連結:http://codevs.cn/problem/2597/
題目:
2597 團伙
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold 題目描述 Description1920年的芝加哥,出現了一群強盜。如果兩個強盜遇上了,那麼他們要麼是朋友,要麼是敵人。而且有一點是肯定的,就是:
我朋友的朋友是我的朋友;
我敵人的敵人也是我的朋友。
兩個強盜是同一團伙的條件是當且僅當他們是朋友。現在給你一些關於強盜們的資訊,問你最多有多少個強盜團伙。
輸入描述 Input Description輸入檔案gangs.in的第一行是一個整數N(2<=N<=1000),表示強盜的個數(從1編號到N)。 第二行M(1<=M<=5000),表示關於強盜的資訊條數。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敵人。輸入資料保證不會產生資訊的矛盾。
輸出描述 Output Description輸出檔案gangs.out只有一行,表示最大可能的團伙數。
樣例輸入 Sample Input6
4
E 1 4
F 3 5
F 4 6
E 1 2
3
2<=N<=1000
1<=M<=5000
1<=p q<=N
這道題是一道並查集的題目。題目的重點在於,如何處理敵人的敵人也是朋友這種情況?朋友的朋友是朋友這很明顯因為他們在同一個等價類裡面,可是敵人的敵人也是朋友就不那麼容易判定了。
我最開始的思路是:先不管它,先把朋友的朋友合併,把敵人關係暫時儲存起來,然後在統一遍歷合併,幸好資料比較水竟然也AC了,不過這麼暴力畢竟不是什麼好方法,所以又百度了一下大神的題解,自己又再行參悟,終於弄懂了大神級別的人的做法:
對敵人的敵人直接進行合併:合併的辦法是,每一個敵人的敵人都用一個數組來表示,並且進行動態地替換。那這時問題就來了,替換能夠對所有需要合併的關係進行合併嗎?會不會有遺漏的情況?
這個時候我們就需要拿起筆畫圖分析一下了:因為朋友的朋友也是朋友,所以當敵人的一個敵人(因為他可能有多個敵人)被我當成朋友之後,雖然只合並了一次,但是其實這個敵人的所有敵人都是朋友了,因為朋友的朋友也是朋友,神奇吧,貼程式碼~
改進之前:
#include <iostream>
#include <cstring>
#include <math.h>
using namespace std;
const int maxn=1005;
int n,m,x,y;
int tree[maxn],counts=0,ans=0;
struct T{
int a,b;
};
char c;
T s[100005];
int find(int aa){
int t=aa;
while(tree[t]!=t){
t=tree[t];
}
int p=aa;
while(p!=t){
int tt=tree[p];
tree[p]=t;
p=tt;
}
return t;
}
void merge(int aa,int bb){
int t,p;
t=find(aa);
p=find(bb);
if(t!=p)
tree[t]=p;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
tree[i]=i;
cin>>m;
for(int i=0;i<m;i++){
cin>>c>>x>>y;
if(c=='F')
merge(x,y);
else{
s[counts].a=x;
s[counts].b=y;
counts++;
}
}
for(int i=0;i<counts;i++)
for(int j=0;j<counts;j++){
if(j!=i){
if(s[i].a==s[j].b)
merge(s[i].b,s[j].a);
else if(s[i].a==s[j].a)
merge(s[i].b,s[j].b);
else if(s[i].b==s[j].a)
merge(s[i].a,s[j].b);
else if(s[i].b==s[j].b)
merge(s[i].a,s[j].a);
}
}
for(int i=1;i<=n;i++)
if(tree[i]==i){
ans++;
}
cout<<ans<<endl;
return 0;
}
改進之後:
#include <iostream>
#include <cstring>
#include <math.h>
using namespace std;
const int maxn=1005;
int n,m,x,y;
int friends[maxn],enemy[maxn],ans;
char c;
int find(int aa){
int t=aa;
while(friends[t]!=t){
t=friends[t];
}
int p=aa;
while(p!=t){
int tt=friends[p];
friends[p]=t;
p=tt;
}
return t;
}
void merge(int a,int b){
int t,p;
t=find(a);
p=find(b);
if(t!=p){
friends[t]=p;
ans--;
}
}
void mergeEnemy(int a,int b){
if(enemy[a]!=0)
merge(b,enemy[a]);
else
enemy[a]=b;
}
int main(){
cin>>n;ans=n;
for(int i=1;i<=n;i++){
friends[i]=i;
enemy[i]=0;
}
cin>>m;
for(int i=0;i<m;i++){
cin>>c>>x>>y;
if(c=='F')
merge(x,y);
else{
mergeEnemy(x,y);
mergeEnemy(y,x);
}
}
cout<<ans<<endl;
return 0;
}
好好學習,天天向上,加油~
相關推薦
CodeVS-2597 團伙(並查集)
題目:CodeVS-2597 題目連結:http://codevs.cn/problem/2597/ 題目: 2597 團伙 時間限制: 1 s 空間限制: 128000 KB
2597 團伙(並查集)
題目描述 Description 1920年的芝加哥,出現了一群強盜。如果兩個強盜遇上了,那麼他們要麼是朋友,要麼是敵人。而且有一點是肯定的,就是: 我朋友的朋友是我的朋友; 我敵人的敵人也是我的朋友。 兩個強盜是同一團伙的條件是當且僅當他們是朋友。現在給你一些
(並查集)Codeforces 325 D-Reclamation
name clam .cn 每次 .html con ret ring true 借用 鏈接 的題意和解法分析的圖片。 對於這種環的形式,先用常用的手段復制一份在右邊。每次加點的過程只要看加完之後能不能通過已有的格子聯通,如果聯通則顯然已經形成了一個環。這裏判斷聯通我
[luoguP2342] 疊積木(並查集)
() click hide open closed include tps 技術 char 傳送門 up[i] 表示一個木塊上面有多少個 all[i] 表示整個連通塊內有多少個 那麽 一個木塊下面的木塊個數為 all[root[i]] - up[i] - 1
hdu5652:India and China Origins(並查集)
and std map printf etc scanf 16px 兩個 for 倒序操作用並查集判斷是否連通,新技能get√(其實以前就會了 這題細節很多。。。搞得整個程序都是調試輸出,幾度看不下去想要重寫 並查集到現在大概掌握了兩個基本用途:判斷是否連通 /
POJ 2492 A Bug's Life (並查集)
ont set -1 flat com rom init red least Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assum
LA 3027 Corporative Network(並查集)
using namespace while += fin clas 都是 ont roo 有n個點,一開始都是孤立的,然後有I,E兩種操作 I u v,把u的父節點設為v,距離為abs(u-v) % 1000,保證u之前沒有父節點 E 詢問u到根節點
HDU 1232 暢通工程 (並查集)
while name style queue input 結束 inf long 城市 某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路
uva live 7638 Number of Connected Components (並查集)
txt 通過 open main eps div cte efi ive 題目鏈接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_
The Suspects (並查集)
self 一點 rate nim 節點 lists tran 並查集 arc 個人心得:最基礎的並查集經典題。借此去了解了一下加深版的即加權並查集,比如食物鏈的題目,這種題目實行起來還是有 一定的難度,不僅要找出與父節點的關系,還要在路徑壓縮的時候進行更新,這一點現在還是沒
POJ-1118 食物鏈(並查集)
ace scan problem tro sca sam 我們 %d 很好 食物鏈 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 75814 Accepted: 22528
CodeForces 445B. DZY Loves Chemistry(並查集)
word other res 技術分享 increase ted weight hit next 轉載請註明出處:http://blog.csdn.net/u012860063?viewmode=contents 題目鏈接:http://codeforces.co
[BZOJ3712]Fiolki 重構樹(並查集)
sample size 不知道 沈澱 過程 表示 deep hellip long 3712: [PA2014]Fiolki Time Limit: 30 Sec Memory Limit: 128 MB Description 化學家吉麗想要配置一種神奇的
Farm Irrigation HDU - 1198 (並查集)
i++ 灌溉 pan isp hdu color img 二進制表示 clu Farm Irrigation HDU - 1198 題意:給11種管道,問草地最少需要打多少個井才可以全部灌溉。 把每種管道的狀態用二進制表示一下,然後對每一塊草地,判斷能否和上面或者左面
Building Block HDU - 2818 (並查集)
freopen return 記錄 scanf splay else 一次 == gif Building Block HDU - 2818 題意:搬磚。。。每一次可以把a所在的那一堆放到b所在的那一堆上面,問第x號磚下面有幾塊磚。 記錄一下到根節點的距離(dw),以
bzoj1015:[JSOI2008]星球大戰starwar(並查集)
ocp smu diy http tex pcc cpp collect tgz 7Q顯19J穎纜賾95拾妨http://www.zcool.com.cn/collection/ZMTg3MzQxNjA=.html h等XKlejV鋅叫斬http://www.zcool.
BZOJ-1854-[Scoi2010]遊戲(並查集)
isp 樹形結構 scanf for 數據 描述 ++ define day Description lxhgww最近迷上了一款遊戲,在遊戲裏,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一
[Bzoj1821][JSOI2010]Group 部落劃分 Group(並查集)(二分答案)
ble 輸出 content 有意 表示 com 自己 clu 我們 1821: [JSOI2010]Group 部落劃分 Group Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2949 Solved:
poj1611 The Suspects(並查集)
con oid sca mes using ++ 如果 problem urn 題目鏈接 http://poj.org/problem?id=1611 題意 有n個學生,編號0~n-1,m個社團,每個社團有k個學生,如果社團裏有1個學生是SARS的疑似患者,則該社團所
Codeforces 915F Imbalance Value of a Tree(並查集)
路徑 second long long air bit force 題意 for href 題目鏈接 Imbalance Value of a Tree 題意 給定一棵樹。求樹上所有簡單路徑中的最大權值與最小權值的差值的和。 首先考慮求所有簡單路徑中的最大權值