[题解]牛跑步

前言:

哈哈,今晚再写一篇题解

并查集双杀

题目描述

新牛到部队,Farmer John要求它们每天早上搞晨跑,从A农场跑到B农场。从A农场到B农场中有n-2个路口,分别标上号,A农场为1号,B农场为n号,路口分别为2...n-1号,从A农场到B农场有很多条路径可以到达,而Farmer John发现有的路口是必须经过的,即每条路径都经过的路口,Farmer John要把它们记录下来,这样Farmer John就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口。

输入输出格式

输入格式:

第一行,两个用空格隔开的整数n(3≤n≤2000)和e(1≤e≤8000)。

接下来从第2到第e+1行,每行两个用空格隔开的整数p和q,表示路口p和q之间有路径直达。

输入数据保证必经路口一定存在,并且每个路口都和A农场、B农场相连通。

输出格式:

第一行,一个整数m,表示必经路口的数目。

第二行,按照从小到大的顺序依次输出每个必经路口的编号,每两个数之间用一个空格隔开。

注意:不包括起点和终点。

输入输出样例

输入样例:
6 6
1 2
2 4
2 3
3 5
4 5
5 6
输出样例:
2
2 5

 题目分析:

我们假如用并查集的思想,枚举每一个节点,清空并查集,将除该割点相关边所连点加入并查集,如果1与n都在此并查集(1、n祖先为一个节点)证明不需要这个割点也可以到达最后,那么这个点就不为必经点。

上面的分析如果没有看懂一定要多看几次,再拿笔推一推,这道题就明了了。
 

代码:

 1 #include<iostream>
 2 #include<fstream>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int Max_N=2e3+5;
 7 const int Max_E=1.6e4+5;
 8 
 9 int n,e,tot,cnt;
10 int Next[Max_E],root[Max_N],to[Max_E];
11 
12 int Fa[Max_N],res[Max_N];
13 
14 void Add_Edge(int u,int v)
15 {
16 //    链式前向星
17     Next[++tot]=root[u];
18     root[u]=tot;
19     to[tot]=v;
20     return ;
21 }
22 void init()
23 {
24 //     初始化并查集
25     register int i;
26     for(i=1;i<=n;i++)
27         Fa[i]=i;
28     return ;
29 }
30 int Find(int p)
31 {
32 //     查找节点祖先
33     if(Fa[p]==p)
34         return p;
35     return Fa[p]=Find(Fa[p]);
36 }
37 void megre(int l,int r)
38 {
39 //     合并两点
40     Fa[Find(l)]=Fa[Find(r)];
41     return ;
42 }
43 void Ge(int p)
44 {
45 //     枚举割点
46     register int i,j;
47     for(i=1;i<=n;i++)
48         if(i^p)
49             for(j=root[i];j^0;j=Next[j])
50                 if(to[j]^p)
51                     megre(i,to[j]);
52     return ;
53 }
54 int main()
55 {
56     scanf("%d%d",&n,&e);
57     register int i;
58     int x,y;
59     for(i=1;i<=e;i++){
60         scanf("%d%d",&x,&y);
61         Add_Edge(x,y);
62         Add_Edge(y,x);
63 //             此图为无向图
64     }
65     int Ans=0;
66     for(i=2;i<n;i++){
67         init();
68         Ge(i);
69         if(Find(1)^Find(n)){
70 //                     不需要该点依然合格
71             Ans++;
72             res[++cnt]=i;
73         }
74     }
75     printf("%d\n",Ans);
76     for(i=1;i<=cnt;i++){
77         if(i>1)
78             printf(" ");
79         printf("%d",res[i]);
80     }
81     return 0;
82 }
代码

 

写在最后的话:

题解仅供思路,要想成为 dalao ,请学会并尽量会做到教他人甚至自己写题解。

博主(目前)是一名初二蒟蒻,如有问题还请大家指出,一起交流学习!

Happy every day!        ——2019.4.11

 
posted @ 2019-04-11 19:22  Happydaylhp  阅读(278)  评论(0编辑  收藏  举报