Road Construction

【题目描述】

某岛屿上有N个旅游景点,任意两个旅游景点之间能够连通,但道路部门正在对某条道路进行施工,禁止游客通行,为了使所有旅游景点依然能够正常开放,道路部门决定搭建一些临时桥梁,使得无论哪条道路正在进行施工,游客都能够到达所有的旅游景点。

现询问至少搭建多少条临时桥梁,在施工期间,游客也能够到达所有的旅游景点。

【输入描述】

第一行输入两个整数N、M(N、M <= 1000),表示景点数目以及道路数目;

接下来M行,每行输入两个整数A、B,表示景点A、B之间存在一条直连道路。

【输出描述】

输出一个数,表示答案。

【输入样例】

样例1:

10 12

1 2

1 3

1 4

2 5

2 6

5 6

3 7

3 8

7 8

4 9

4 10

9 10

样例2:

3 3

1 2

2 3

1 3

【输出样例】

样例1:

2

样例2:

0

源代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
vector <int> List[1001];
int n,m,Num(0),Ans(0),i[1001],j[1001],Vis[1001],Sum[1001];
void DFS(int t,int Father) //稍加修改的Tarjan。
{
    Vis[t]=1;
    j[t]=i[t]=++Num;
    for (int a=0;a<List[t].size();a++)
    {
        int T=List[t][a];
        if (Vis[T]==1&&T!=Father) //防重复,其实想一想,朴素Tarjan的Instack()其实也如此。
          i[t]=min(i[t],j[T]);
        if (!Vis[T])
        {
            DFS(T,t);
            i[t]=min(i[t],i[T]);
        }
    }
    Vis[t]=2; //其实加不加都无所谓,Vis[0]、Vis[1]、Vis[2]分别表示未遍历、遍历过但子节点未访问完、遍历过且子节点已访问完。
}
int main()
{
    scanf("%d%d",&n,&m);
    while (m--)
    {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        List[t1].push_back(t2);
        List[t2].push_back(t1);
    }
    DFS(1,1);
    for (int a=1;a<=n;a++)
      for (int b=0;b<List[a].size();b++)
        if (i[a]!=i[List[a][b]]) //两个相连的节点不在同一个强连通分量中。
          Sum[i[a]]++; //统计源节点的,也算是出度吧。
    for (int a=1;a<=n;a++)
      printf("%d %d
",i[a],Sum[a]);
    for (int a=1;a<=n;a++)
      if (Sum[a]==1) //若强连通分量之间只有一条连边,那么必为桥。
        Ans++;
    printf("%d",Ans+1>>1); //因为是无向图,所以重复了一倍。
    return 0;
}
原文地址:https://www.cnblogs.com/Ackermann/p/5982953.html