牛客练习赛32 D Tarjan无向图求桥+并查集维护

题目描述:

小p和他的朋友约定好去游乐场游玩,但是他们到了游乐场后却互相找不到对方了。
游乐场可以看做是一张n个点,m条道路的图,每条道路有边权wi,表示第一次经过该道路时的花费(第二次及以后经过时花费为0)。
现在,小p要去找他的朋友,但他的朋友行踪很诡异,小p总是要遍历完这n个点才能找到他,同时小p希望总花费最小。
找到朋友的方案可能不唯一(具体看样例解释),小p想知道在这所有的方案中,有多少条边在每个方案中都会被经过。
 

输入描述:

第一行两个整数n, m. p,分别表示点数,边数,小p的初始位置。
接下来m行,每行两个整数u, v, w表示从u到v有一条无向边,边权为w。

输出描述:

输出一个整数k,表示必须经过的边的数量。

示例1

输入

5 7 1
1 2 3
2 3 7
1 3 5
2 4 2
1 5 3
5 4 3
2 5 3

输出

2

样例解释:

 

牛客练习赛32 D Tarjan无向图求桥+并查集维护_第1张图片
几种可能的方案如下:




可以证明,4 - 2和1 - 3这两条边在所有方案中都被经过。
(以上每种方案的总花费均为13,同时可以证明没有比这更优的策略)

示例2

输入

3 3 1
1 2 1
1 3 1
2 3 2

输出

2

示例3

输入

3 3 1
1 2 2
2 3 2
1 3 2

输出

0

备注:

保证图联通,保证无自环,保证无重边

链接:https://ac.nowcoder.com/acm/contest/272/D
来源:牛客网

简单来说就是寻找有几条边一定在最小生成树上

将路径按照权值排序后,按照权值由小到大的顺序将点增加到最小生成树中,使用并查集维护图的连通性

如果路径权值相等,路径两个端点已经在连通图中,那么不用添加这条边

如果两个端点不在连通图中,那么将边添加到新图中,然后使用Tarjan算法求解出无向图中的桥,即一定存在于最小生成树中的边

#include 
#include 
#include 
#include 
#include 

using namespace std;
typedef long long ll;
const int maxn = 200100;
int n,m,s;
vector > v[maxn];      //v[x] 表示以x开始的节点,pair.first表示边到达的节点,pair.second表示边的编号
struct Edge
{
    int u,v,w,id;
    bool operator<(const Edge&a)const
    {
        return w < a.w;
    }
}edge[maxn];
int dfn[maxn],low[maxn],k,per[maxn],ans[maxn];

void tarjan(int x,int fa)          //Tarjan求解图中的桥
{
    dfn[x] = low[x] = ++k;
    for(int i = 0,to,id;i < v[x].size();i ++)
    {
        if((id = v[x][i].second) == fa) continue;        //路径返回了回去,不用考虑
        to = v[x][i].first;
        if(!dfn[to]){
            tarjan(to,id);low[x] = min(low[x],low[to]);
            if(low[to] > dfn[x]) ans[id] = 1,cout<

 

你可能感兴趣的:(Tarjan)