1. 合根植物
w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。
格子的编号一行一行,从上到下,从左到右编号。
比如:5 * 4 的小格子,编号:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
样例输入
5 4
16
2 3
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17
样例输出
5
样例说明
其合根情况参考下图
思路: 很简单的并查集题目。
1 #include <iostream> 2 3 using namespace std; 4 int m,n,sum; 5 int pre[1000005]; 6 void init() 7 { 8 for(int i=1;i<=sum;i++) 9 pre[i] = i; 10 } 11 int find_pre(int x) 12 { 13 if(x==pre[x]) 14 return x; 15 else 16 return pre[x] = find_pre(pre[x]); 17 } 18 bool Union(int x,int y) 19 { 20 int rootx = find_pre(x),rooty = find_pre(y); 21 if(rootx != rooty) 22 { 23 pre[rootx] = rooty; 24 return true; 25 } 26 return false; 27 } 28 int main() 29 { 30 int k,a,b; 31 scanf("%d %d",&m,&n); 32 sum = m*n; 33 scanf("%d",&k); 34 init(); 35 for(int i=0;i<k;i++) 36 { 37 scanf("%d %d",&a,&b); 38 if(Union(a,b)) 39 sum--; 40 } 41 printf("%d\n",sum); 42 return 0; 43 }
2. 国王的烦恼
C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。
如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。
现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。
输入格式
输入的第一行包含两个整数n, m,分别表示小岛的个数和桥的数量。
接下来m行,每行三个整数a, b, t,分别表示该座桥连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。
输出格式
输出一个整数,表示居民们会抗议的天数。
样例输入
4 4
1 2 2
1 3 2
2 3 1
3 4 3
样例输出
2
样例说明
第一天后2和3之间的桥不能使用,不影响。
第二天后1和2之间,以及1和3之间的桥不能使用,居民们会抗议。
第三天后3和4之间的桥不能使用,居民们会抗议。
数据规模和约定
对于30%的数据,1<=n<=20,1<=m<=100;
对于50%的数据,1<=n<=500,1<=m<=10000;
对于100%的数据,1<=n<=10000,1<=m<=100000,1<=a, b<=n, 1<=t<=100000。
思路:桥坏的过程是一个单集合转化为多集合的过程,这个过程和并查集刚好相反,所以这道题需要逆推,将桥坏的过程转化为建桥的过程。首先设定一个数据结构,保存桥和桥坏的时间,然后按照桥坏的时间给这个结构体排序(倒叙)。如果桥建立以后,两座岛由两个集合合并为一个集合,则等价于这座桥坏了以后,两座岛不再在一个集合内,这个时候居民就要抗议。
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 struct line{ 5 int a,b,t; 6 line(int a,int b,int t):a(a),b(b),t(t){} 7 line(){} 8 bool operator<(const line&b) 9 { 10 return t>b.t; 11 } 12 }s[100005]; 13 int pre[10005]; 14 int sum = 0,n,m; 15 void init() 16 { 17 for(int i=1;i<=n;i++) 18 pre[i] = i; 19 } 20 int find_pre(int x) 21 { 22 if(x==pre[x]) 23 return x; 24 else 25 return pre[x] = find_pre(pre[x]); 26 } 27 bool Union(int x,int y) 28 { 29 int rootx = find_pre(x),rooty = find_pre(y); 30 if(rootx != rooty) 31 { 32 pre[rootx] = rooty; 33 return true; 34 } 35 return false; 36 } 37 int main() 38 { 39 scanf("%d %d",&n,&m); 40 init(); 41 int a,b,t; 42 for(int i=1;i<=m;i++) 43 { 44 scanf("%d %d %d",&a,&b,&t); 45 s[i] = line(a,b,t); 46 } 47 sort(s+1,s+n+1); 48 int lastday = 0; 49 for(int i=1;i<=m;i++) 50 { 51 if(Union(s[i].a,s[i].b)&&(lastday!=s[i].t)) sum++; 52 lastday = s[i].t; 53 } 54 printf("%d\n",sum); 55 return 0; 56 }