发现环

原创


问题描述
  小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
  不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
  为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
输入格式
  第一行包含一个整数N。
  以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。
  对于30%的数据,1 <= N <= 1000
  对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N
  输入保证合法。
输出格式
  按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。
样例输入
5
1 2
3 1
2 4
2 5
5 3
样例输出
1 2 3 5
 
  思路:并查集+DFS,在读入边的同时判断边的两个结点是否属于同一个集合,若属于同一个集合则说明这两个结点
是环上的两个结点(很好理解,可以自己画图试试),将这两个结点作为起点和终点,从起点开始深搜,到终点的路径
上的所有结点就是环上的结点。
  题目很好理解,在图中找一个环(有且只有一个),之前直接用暴力深搜解答过,放到官网运行超时。
超时的原因有两个:
  一:之前我没有用合理的数据结构存储图,直接用了数组来存储边,然后每次搜索都要搜索整张图,很浪费时间,
今天刚学习到可以用vector存储图(其实就像是二维矩阵一样),每个结点都拥有一个属于自己的容器,容器里面存储
着与其直接相连的结点。
  二:没有使用并查集,不知道哪个结点在环上,只能一个一个结点的去试。
  有点纳闷,用C++写可以AC,用JAVA写没有用vector超时!
C++
 1 #include <stdio.h>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 const int maxn=100005;
 6 
 7 int N;
 8 int qi_Dian;    //深搜起点 
 9 int zhong_Dian;    //深搜终点 
10 int father[maxn];    //存储每个结点的父结点  
11 int way[maxn];    //存储路径
12 int book[maxn];    //访问与否 
13 int total;    //存储环上结点总数 
14 int flag=0;
15 vector<int> matrix[maxn];    //二维容器vector 
16 
17 //寻找父结点 
18 int find_Father(int spot){
19     return spot==father[spot]?spot:father[spot]=find_Father( father[spot] );
20 }
21 
22 void dfs(int spot,int count){    //spot代表结点,count代表way[count] 
23     if(spot==zhong_Dian){
24         flag=1;
25         total=count-1;
26         return;
27     }
28     for(int i=0;i<matrix[spot].size();i++){
29         int v=matrix[spot][i];
30         if(book[v]==0){
31             book[v]=1;
32             way[count]=v;
33             dfs(v,count+1);
34             if(flag==1){
35                 return;
36             }
37             book[v]=0;
38         }
39     }
40 }
41 
42 int main(){
43     scanf("%d",&N);
44     //并查集初始化
45     for(int i=1;i<=N;i++){
46         father[i]=i;
47     }
48     //读入边
49     for(int i=1;i<=N;i++){
50         int one;    //第一条边 
51         int two;    //第二条边 
52         scanf("%d%d",&one,&two);
53         int one_Father=find_Father(one);
54         int two_Father=find_Father(two);
55         //判断头结点是否相等,相等则赋值为起点终点 
56         if(one_Father==two_Father){
57             qi_Dian=one;
58             zhong_Dian=two;
59         }
60         else{    //不相等则并合并 
61             father[two_Father]=one_Father;
62             //压入容器,相当于二维邻接矩阵 
63             matrix[one].push_back(two);
64             matrix[two].push_back(one);
65         } 
66     } 
67     //开始深搜
68     book[qi_Dian]=1;
69     way[1]=qi_Dian;
70     dfs(qi_Dian,2);
71     sort(way,way+total+1);
72     for(int i=1;i<=total;i++){
73         printf("%d ",way[i]);
74     }
75     return 0;
76 }

JAVA

 1 import java.util.*;
 2 import java.util.Arrays;
 3 
 4 public class Main {
 5     
 6     static int N;
 7     static int matrix[][];    //邻接矩阵
 8     static int book[][];    //标记边是否遍历
 9     static int father[];
10     static int qi_Dian;    //起点
11     static int zhong_Dian;    //终点
12     static int way[];    //存储路径
13     static int flag=0;
14     static int total;
15 
16     //寻找父结点
17     static int find_Father(int spot) {
18         if(spot!=father[spot]) {
19             return father[spot]=find_Father( father[spot] );
20         }
21         return spot;
22     }
23     
24     static void dfs(int spot,int count) {    //点spot,count为路径数组索引
25         //终点判断
26         if(spot==zhong_Dian) {
27             total=count-1;
28             flag=1;
29             return;
30         }
31         for(int i=1;i<=N;i++) {
32             //起点和终点不能直接相连
33             if(spot==qi_Dian && i==zhong_Dian) {
34                 continue;
35             }
36             if(matrix[spot][i]==1 && book[spot][i]==0) {
37                 book[spot][i]=1;
38                 book[i][spot]=1;
39                 way[count]=i;
40                 dfs(i,count+1);
41                 if(flag==1) {
42                     return;
43                 }
44                 book[spot][i]=0;
45                 book[i][spot]=0;
46             }
47         }
48     }
49 
50     public static void main(String[] args) {
51         Scanner reader=new Scanner(System.in);
52         N=reader.nextInt();
53         matrix=new int[N+1][N+1];
54         father=new int[N+1];
55         book=new int[N+1][N+1];
56         way=new int[N+1];    //最多有N个结点
57         //结点指向本身(并查集初始化)
58         for(int i=1;i<=N;i++) {
59             father[i]=i;
60         }
61         //读入边
62         for(int i=1;i<=N;i++) {
63             int one=reader.nextInt();
64             int two=reader.nextInt();
65             matrix[one][two]=1;
66             matrix[two][one]=1;
67             //寻找这两个结点的父结点
68             int one_Father=find_Father(one);
69             int two_Father=find_Father(two);
70             //判断两个头结点是否相等,不相等合并
71             if(one_Father!=two_Father) {
72                 father[two_Father]=one_Father;
73             }
74             //相等,赋值为深搜的起点和终点
75             else if(one_Father==two_Father) {
76                 qi_Dian=one;
77                 zhong_Dian=two;
78             }
79         }
80         way[1]=qi_Dian;
81         dfs(qi_Dian,2);    //从起点开始深搜,找到终点结束
82         Arrays.sort(way,0,total+1);
83         for(int i=1;i<=total;i++) {
84             System.out.print(way[i]+" ");
85         }
86     }
87 
88 }

14:34:40

2018-08-14

原文地址:https://www.cnblogs.com/chiweiming/p/9474394.html