• [题解]牛跑步


    前言:

    哈哈,今晚再写一篇题解

    并查集双杀

    题目描述

    新牛到部队,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
    ",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

     
  • 相关阅读:
    FreeSql.Repository (九)级联保存
    FreeSql.Repository (八)级联加载
    FreeSql.Repository (七)多表查询
    FreeSql.Repository (六)导航属性
    FreeSql.Repository (五)状态管理
    FreeSql.Repository (四)工作单元
    FreeSql.Repository (三)实体特性
    FreeSql.Repository (一)什么是仓储
    [开源] .Net 使用 ORM 访问 华为GaussDB数据库
    24位PCM采样数据转成16位算法,已实现PCM转WAV在线工具源码支持24bits、16bits、8bits
  • 原文地址:https://www.cnblogs.com/lihepei/p/10691795.html
Copyright © 2020-2023  润新知