1. 程式人生 > >CodeVS-2597 團伙(並查集)

CodeVS-2597 團伙(並查集)

題目:CodeVS-2597

題目連結:http://codevs.cn/problem/2597/

題目:

2597 團伙

 時間限制: 1 s  空間限制: 128000 KB  題目等級 : 黃金 Gold 題目描述 Description

1920年的芝加哥,出現了一群強盜。如果兩個強盜遇上了,那麼他們要麼是朋友,要麼是敵人。而且有一點是肯定的,就是:

我朋友的朋友是我的朋友;

我敵人的敵人也是我的朋友。 

兩個強盜是同一團伙的條件是當且僅當他們是朋友。現在給你一些關於強盜們的資訊,問你最多有多少個強盜團伙。

輸入描述 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 Input

6
4
E 1 4
F 3 5
F 4 6
E 1 2

樣例輸出 Sample Output

3

資料範圍及提示 Data Size & Hint

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 題意 給定一棵樹。求樹上所有簡單路徑中的最大權值與最小權值的差值的和。 首先考慮求所有簡單路徑中的最大權值