并查集入门三连:HDU1213 POJ1611 POJ2236
HDU1213
http://acm.hdu.edu.cn/showproblem.php?pid=1213
問(wèn)題描述
今天是伊格納修斯的生日。他邀請(qǐng)了很多朋友。現(xiàn)在是晚餐時(shí)間。伊格納修斯想知道他至少需要多少桌子。你必須注意到并非所有的朋友都互相認(rèn)識(shí),而且所有的朋友都不想和陌生人呆在一起。
這個(gè)問(wèn)題的一個(gè)重要規(guī)則是,如果我告訴你A知道B,B知道C,那意味著A,B,C彼此了解,所以他們可以留在一個(gè)表中。
例如:如果我告訴你A知道B,B知道C,D知道E,所以A,B,C可以留在一個(gè)表中,D,E必須留在另一個(gè)表中。所以Ignatius至少需要2張桌子。
輸入
輸入以整數(shù)T(1 <= T <= 25)開(kāi)始,表示測(cè)試用例的數(shù)量。然后是T測(cè)試案例。每個(gè)測(cè)試用例以?xún)蓚€(gè)整數(shù)N和M開(kāi)始(1 <= N,M <= 1000)。N表示朋友的數(shù)量,朋友從1到N標(biāo)記。然后M行跟隨。每一行由兩個(gè)整數(shù)A和B(A!= B)組成,這意味著朋友A和朋友B彼此了解。兩個(gè)案例之間會(huì)有一個(gè)空白行。
?
對(duì)于每個(gè)測(cè)試用例,只輸出Ignatius至少需要多少個(gè)表。不要打印任何空白。
樣本輸入
2
5 3
1 2
2 3
4 5
?
5 1
2 5
樣本輸出
2
4
并查集基礎(chǔ)題
#include<cstdio> #include<iostream> using namespace std; int fa[1005]; int n,m; void init()//初始化 {for(int i=0;i<1005;i++)fa[i]=i; } int find(int x)//尋根 {if(fa[x]!=x)fa[x]=find(fa[x]);return fa[x]; } void union(int x,int y)//判斷、合并 {int a=find(x),b=find(y);if(a!=b)fa[b]=a; } int main() {int t;scanf("%d",&t);while(t--){int a,b,cnt=0;scanf("%d%d",&n,&m);init();for(int i=1;i<=m;i++)//合并{scanf("%d%d",&a,&b);union(a,b);}for(int i=1;i<=n;i++)//統(tǒng)計(jì){find(i);if(find(i)==i)cnt++;}printf("%d\n",cnt);}return 0; }POJ1611
http://poj.org/problem?id=1611
描述
嚴(yán)重急性呼吸系統(tǒng)綜合癥(SARS)是一種病因不明的非典型肺炎,在2003年3月中旬被認(rèn)為是一種全球性威脅。為了盡量減少對(duì)他人的傳播,最好的策略是將嫌疑人與其他嫌疑人分開(kāi)。?
在Not-Spreading-Your-Sickness University(NSYSU),有許多學(xué)生團(tuán)體。同一組中的學(xué)生經(jīng)常互相交流,學(xué)生可以加入幾個(gè)小組。為了防止可能的SARS傳播,NSYSU收集所有學(xué)生組的成員列表,并在其標(biāo)準(zhǔn)操作程序(SOP)中制定以下規(guī)則。?
一旦組中的成員是嫌疑人,該組中的所有成員都是嫌疑人。?
然而,他們發(fā)現(xiàn),當(dāng)學(xué)生被認(rèn)定為嫌疑人時(shí),識(shí)別所有嫌疑人并不容易。你的工作是編寫(xiě)一個(gè)找到所有嫌疑人的程序。
輸入
輸入文件包含幾種情況。每個(gè)測(cè)試用例以一行中的兩個(gè)整數(shù)n和m開(kāi)始,其中n是學(xué)生數(shù),m是組的數(shù)量。您可以假設(shè)0 <n <= 30000且0 <= m <= 500.每個(gè)學(xué)生都使用0到n-1之間的唯一整數(shù)進(jìn)行編號(hào),并且最初學(xué)生0在所有情況下都被識(shí)別為嫌疑人。該行后面是組的m個(gè)成員列表,每組一行。每行以整數(shù)k開(kāi)頭,表示組中的成員數(shù)。在成員數(shù)量之后,有k個(gè)整數(shù)代表該組中的學(xué)生。一行中的所有整數(shù)由至少一個(gè)空格分隔。?
n = 0且m = 0的情況表示輸入結(jié)束,無(wú)需處理。
?
對(duì)于每種情況,輸出一行中的嫌疑人數(shù)量。
樣本輸入
100 4 2 1 2 5 10 13 11 12 14 2 0 1 2 99 2 200 2 1 5 5 1 2 3 4 5 1 0 0 0樣本輸出
4 1 1?
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include <string> using namespace std; int a[30001],pre[30001]; int find(int x)//尋根 {if(pre[x]==x)return x;elsereturn pre[x]=find(pre[x]); } void union(int x, int y)//合并 {int fx = find(x), fy = find(y);if (fx != fy)pre[fy] = fx; }int main() {int n,m;while (scanf("%d%d", &n, &m) != EOF && (n || m)){int sum = 0;for (int i = 0; i < n; i++)//初始化pre[i] = i;for (int i = 0; i < m; i++){int k;scanf("%d", &k);if (k >= 1){scanf("%d", &a[0]);for (int j = 1; j < k; j++){scanf("%d", &a[j]);//接收union(a[0], a[j]);//和0號(hào)一組}}}for (int i = 0; i < n; i++)//統(tǒng)計(jì)if (find(i) ==pre[0])sum++;printf("%d\n", sum);}return 0; }?POJ2236
http://poj.org/problem?id=2236
描述
地震發(fā)生在東南亞。ACM(亞洲合作醫(yī)療團(tuán)隊(duì))已經(jīng)與膝上電腦建立了無(wú)線(xiàn)網(wǎng)絡(luò),但是一次意外的余震襲擊,網(wǎng)絡(luò)中的所有計(jì)算機(jī)都被打破了。計(jì)算機(jī)一個(gè)接一個(gè)地修復(fù),網(wǎng)絡(luò)逐漸開(kāi)始工作。由于硬件限制,每臺(tái)計(jì)算機(jī)只能直接與距離它不遠(yuǎn)的計(jì)算機(jī)進(jìn)行通信。但是,每臺(tái)計(jì)算機(jī)都可以被視為兩臺(tái)計(jì)算機(jī)之間通信的中介,也就是說(shuō),如果計(jì)算機(jī)A和計(jì)算機(jī)B可以直接通信,或者計(jì)算機(jī)C可以與A和A進(jìn)行通信,則計(jì)算機(jī)A和計(jì)算機(jī)B可以進(jìn)行通信。 B.?
在修復(fù)網(wǎng)絡(luò)的過(guò)程中,工作人員可以隨時(shí)進(jìn)行兩種操作,修復(fù)計(jì)算機(jī)或測(cè)試兩臺(tái)計(jì)算機(jī)是否可以通信。你的工作是回答所有的測(cè)試操作。?
輸入
第一行包含兩個(gè)整數(shù)N和d(1 <= N <= 1001,0 <= d <= 20000)。這里N是計(jì)算機(jī)的數(shù)量,編號(hào)從1到N,D是兩臺(tái)計(jì)算機(jī)可以直接通信的最大距離。在接下來(lái)的N行中,每行包含兩個(gè)整數(shù)xi,yi(0 <= xi,yi <= 10000),這是N臺(tái)計(jì)算機(jī)的坐標(biāo)。從第(N + 1)行到輸入結(jié)束,有一些操作,這些操作是一個(gè)接一個(gè)地執(zhí)行的。每行包含以下兩種格式之一的操作:?
1。“O p”(1 <= p <= N),表示修復(fù)計(jì)算機(jī)p。?
2.“S p q”(1 <= p,q <= N),這意味著測(cè)試計(jì)算機(jī)p和q是否可以通信。?
輸入不會(huì)超過(guò)300000行。?
產(chǎn)量
對(duì)于每個(gè)測(cè)試操作,如果兩臺(tái)計(jì)算機(jī)可以通信則打印“SUCCESS”,否則打印“FAIL”。
樣本輸入
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4樣本輸出
FAIL SUCCESS?思路:對(duì)每次修好的電腦對(duì)其它已經(jīng)修好的電腦遍歷,如果距離小于等于最大通信距離就將他們合并。
注意:
1、坐標(biāo)之后給出的計(jì)算機(jī)編號(hào)都是n+1的。例如O 3,他實(shí)際上修理的是編號(hào)為2的計(jì)算機(jī),因?yàn)橛?jì)算機(jī)是從0開(kāi)始編號(hào)的。
2、比較距離的時(shí)候注意要用浮點(diǎn)數(shù)比較,否則會(huì)WA。
3、"FAIL"不要寫(xiě)成"FALL"。
4、字符串輸入的時(shí)候注意處理好回車(chē),空格等情況。
5、注意N的范圍(1 <= N <= 1001),最大是1001,不是1000。是個(gè)小坑,數(shù)組開(kāi)小了可能會(huì)錯(cuò)哦。
?
#include <iostream> #include <stdio.h> #include <cmath> using namespace std;#define MAXN 1010int dx[MAXN],dy[MAXN]; //坐標(biāo) int par[MAXN]; //x的父節(jié)點(diǎn) int repair[MAXN] ={0}; int n;void Init()//初始化 {int i;for(i=0;i<=n;i++)par[i] = i; }int Find(int x)//尋根 {if(par[x]!=x)par[x] = Find(par[x]);return par[x]; }void Union(int x,int y)//合并 {par[Find(x)] = Find(y); }int Abs(int n)//絕對(duì)值 {return n>0?n:-n; }double Dis(int a,int b)//坐標(biāo) {return sqrt( double(dx[a]-dx[b])*(dx[a]-dx[b]) + (dy[a]-dy[b])*(dy[a]-dy[b]) ); }int main() {int d,i;//初始化scanf("%d%d",&n,&d);Init();//輸入坐標(biāo)for(i=0;i<n;i++){scanf("%d%d",&dx[i],&dy[i]);}//操作char cmd[2];int p,q,len=0;while(scanf("%s",cmd)!=EOF){switch(cmd[0]){case 'O':scanf("%d",&p);p--;repair[len++] = p;for(i=0;i<len-1;i++) //遍歷所有修過(guò)的計(jì)算機(jī),看能否聯(lián)通if( repair[i]!=p && Dis(repair[i],p)<=double(d) )Union(repair[i],p);break;case 'S':scanf("%d%d",&p,&q);p--,q--;if(Find(p)==Find(q)) //判斷printf("SUCCESS\n");else printf("FAIL\n");default:break;}}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的并查集入门三连:HDU1213 POJ1611 POJ2236的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c语言知识体系
- 下一篇: 图的基本概念【数据结构】