九度oj 题目1109:连通图
- 题目描述:
-
给定一个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。
- 输入:
-
每组数据的第一行是两个整数 n 和 m(0<=n<=1000)。n 表示图的顶点数目,m 表示图中边的数目。如果 n 为 0 表示输入结束。随后有 m 行数据,每行有两个值 x 和 y(0<x, y <=n),表示顶点 x 和 y 相连,顶点的编号从 1 开始计算。输入不保证这些边是否重复。
- 输出:
-
对于每组输入数据,如果所有顶点都是连通的,输出"YES",否则输出"NO"。
- 样例输入:
-
4 3 1 2 2 3 3 2 3 2 1 2 2 3 0 0
- 样例输出:
-
NO YES
这个题一开始用深度优先搜索做的,代码如下1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 int map[1002][1002]; 6 int flag[1002]; 7 int n, m; 8 9 void dfs(int k) { 10 flag[k] = 1; 11 for(int i = 1; i <= n; i++) { 12 if(flag[i] == 0 && map[k][i] == 1) { 13 dfs(i); 14 } 15 } 16 } 17 18 int main(int argc, char const *argv[]) 19 { 20 //freopen("input.txt","r",stdin); 21 while(scanf("%d %d",&n,&m) != EOF && n != 0) { 22 memset(map,0, sizeof(map)); 23 memset(flag, 0, sizeof(flag)); 24 25 while(m--) { 26 int a, b; 27 scanf("%d %d",&a, &b); 28 map[a][b] = map[b][a] = 1; 29 } 30 flag[1] = 1; 31 dfs(1); 32 bool isOk = true; 33 for(int i = 1; i <=n; i++) { 34 if(flag[i] == 0) { 35 isOk = false; 36 break; 37 } 38 } 39 if(isOk) { 40 puts("YES"); 41 } 42 else { 43 puts("NO"); 44 } 45 46 } 47 return 0; 48 }
但耗时略长,内存占用略大
后来试了试迪杰特斯拉算法的变形
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 int map[1002][1002]; 6 int flag[1002]; 7 int n, m; 8 9 void dfs(int k) { 10 flag[k] = 1; 11 for(int i = 1; i <= n; i++) { 12 if(flag[i] == 0 && map[k][i] == 1) { 13 dfs(i); 14 } 15 } 16 } 17 18 int main(int argc, char const *argv[]) 19 { 20 freopen("input.txt","r",stdin); 21 while(scanf("%d %d",&n,&m) != EOF && n != 0) { 22 memset(map,0, sizeof(map)); 23 memset(flag, 0, sizeof(flag)); 24 25 while(m--) { 26 int a, b; 27 scanf("%d %d",&a, &b); 28 map[a][b] = map[b][a] = 1; 29 } 30 flag[1] = 1; 31 32 for(int i = 2; i <= n; i++) { 33 for(int j = 1; j <= n; j++) { 34 if(flag[j] == 0 && map[1][j] == 1) { 35 flag[j] = 1; 36 for(int k = 1; k <= n; k++) { 37 if(map[j][k] == 1) { 38 map[1][k] = 1; 39 } 40 } 41 } 42 } 43 } 44 45 bool isOk = true; 46 for(int i = 1; i <=n; i++) { 47 if(flag[i] == 0) { 48 isOk = false; 49 break; 50 } 51 } 52 if(isOk) { 53 puts("YES"); 54 } 55 else { 56 puts("NO"); 57 } 58 59 } 60 return 0; 61 }
但耗时更长
也试了试flyod算法
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 int map[1002][1002]; 6 int n, m; 7 8 int main(int argc, char const *argv[]) 9 { 10 //freopen("input.txt","r",stdin); 11 while(scanf("%d %d",&n,&m) != EOF && n != 0) { 12 memset(map,0, sizeof(map)); 13 14 while(m--) { 15 int a, b; 16 scanf("%d %d",&a, &b); 17 map[a][b] = map[b][a] = 1; 18 } 19 map[1][1] = 1; 20 for(int i = 1; i <= n; i++) { 21 for(int j = 1; j <= n; j++) { 22 for(int k = 1; k <= n; k++) { 23 if(map[j][i] == 1 && map[i][k] == 1) { 24 map[j][k] = 1; 25 } 26 } 27 } 28 } 29 30 31 bool isOk = true; 32 for(int i = 1; i <=n; i++) { 33 if(map[1][i] == 0) { 34 isOk = false; 35 break; 36 } 37 } 38 if(isOk) { 39 puts("YES"); 40 } 41 else { 42 puts("NO"); 43 } 44 45 } 46 return 0; 47 }
直接超时了
突然会想起一个月前做的题,好像叫做并查集的东西,代码如下
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 5 int next[1002]; 6 int n, m; 7 8 int find(int t) { 9 while(next[t] != 0) { 10 t = next[t]; 11 } 12 return t; 13 } 14 15 int main(int argc, char const *argv[]) 16 { 17 //freopen("input.txt","r",stdin); 18 while(scanf("%d %d",&n,&m) != EOF && n != 0) { 19 memset(next, 0, sizeof(next)); 20 21 while(m--) { 22 int a, b; 23 scanf("%d %d",&a, &b); 24 int fa = find(a); 25 int fb = find(b); 26 if(fa != fb) { 27 next[fa] = b; 28 } 29 } 30 31 int isOk = 0; 32 for(int i = 1; i <= n; i++) { 33 if(next[i] == 0) { 34 isOk++; 35 if(isOk >= 2) { 36 puts("NO"); 37 break; 38 } 39 } 40 } 41 if(isOk == 1) { 42 puts("YES"); 43 } 44 45 } 46 return 0; 47 }
耗时和内存都有质的飞跃,但如何再进一步优化呢?