题目大意:

https://ac.nowcoder.com/acm/contest/272/D

在一个无向图中,给定一个起点,从起点开始走遍图中所有点

每条边有边权wi,表示第一次经过该道路时的花费(第二次及以后经过时花费为0)

此时用最少花费完成可能存在多种方案

求每种方案都必须经过的边有多少条

首先想到最小生成树

然后想到在得到最短边时 若存在其他长度相等的边 这条边此时就可被替代

但如果没有长度相等的边 那么这条边就是必须经过的边

然而这个想法经不起考验 是错误的 如下

但是没有长度相等的边 就是必须经过的边 这是毋庸置疑的

那么再观察下图

可以看到这是 一个只由长度相等的边组成的图

若在这个图中 我们要得到一棵生成树的话 边3-4是必选的 而剩下的1-2、2-3、3-1则任选两条即可

也就是说在生成树的所有选择方案里 这三条边不是必须经过的边

那么可以发现 在一个只由长度相等的边组成的图内 能形成一个环的几条边不是在所有的选择方案里必须经过的边

再结合kruskal得到最小生成树的步骤 每次先得到所有相同长度的最短边建图

再找到其中的环的个数m 那么要连接所有的环 必须经过的边就有m-1条

tarjan 求无向图内的环 就是在 有向图求强联通分量 的基础上进行修改

将 已走过的边 视为有向 不走其反向边

那么当走完这个图之后 整个图变成了一个有向图 此时图中的强联通分量就是环

如何 将已走过的边视为有向 呢

首先建图的过程中 对于一条边 我们是连了正向就连反向的 也就是这两条有向边在存储过程中的序号是连续的

所以我们从序号2开始存边的话 序号为 2和3 的两条有向边对应一条无向边 4和5对应一条无向边 6和7对应一条......

则对于 存储顺序为第 x 的有向边 其对应的反向边(即另一条有向边)顺序为 (x^1)

那么我们在递归时将上一条边的顺序 last 作为参数传过来 不走它对应的反向边即跳过顺序为 last^1 的边 就可以了

#include <bits/stdc++.h>
#define mem(i,j) memset(i,j,sizeof(i))
using namespace std;
const int N=2e5+; struct EDGE {
int u,v,w;
bool operator <(const EDGE& p)const {
return w<p.w;
}
}E[N<<];
struct NODE { int to,nt; }e[N<<];
int head[N], tot;
void addE(int u,int v) {
e[++tot].to=v;
e[tot].nt=head[u];
head[u]=tot;
}
int dfn[N], low[N], ind;
int fa[N], ans;
int n, m, p;
void init_e() {
ind=; mem(dfn,);
tot=; mem(head,);
}
void init_s() {
ans=;
for(int i=;i<=n;i++) fa[i]=i;
} int tarjan(int u,int last) {
dfn[u]=low[u]=++ind;
int res=;
for(int i=head[u];i;i=e[i].nt) {
if(i==(last^)) continue; // 是上一条边的对应反向边 跳过
int v=e[i].to;
if(!dfn[v]) {
res+=tarjan(v,i);
low[u]=min(low[u],low[v]);
} else low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]) res++;
return res;
} int getfa(int x) {
if(x==fa[x]) return x;
return fa[x]=getfa(fa[x]);
}
void unite(int x,int y) {
x=getfa(x), y=getfa(y);
if(x!=y) fa[x]=y;
} void Kruskal() {
sort(E,E+m);
for(int i=,j;i<m;i=j) {
j=i;
while(j<m && E[j].w==E[i].w) j++; //找到所有与最短边相等的边
init_e(); // 初始化邻接表和tarjan需要的数组
for(int k=i;k<j;k++) { // 建图
int u=getfa(E[k].u), v=getfa(E[k].v);
if(u==v) continue; // 两个点已经连起来了
addE(u,v); addE(v,u);
}
for(int k=i;k<j;k++) {
int u=getfa(E[k].u);
if(!dfn[u]) ans+=tarjan(u,)-; //保证m个环连通 需要m-1条边
}
for(int k=i;k<j;k++)
unite(E[k].u,E[k].v);
}
} int main()
{
while(~scanf("%d%d%d",&n,&m,&p)) {
init_s();
for(int i=;i<m;i++)
scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
Kruskal();
printf("%d\n",ans);
} return ;
}

牛客D-Where are you /// kruskal+tarjan找无向图内的环的更多相关文章

  1. 牛客小白月赛12 I (tarjan求割边)

    题目链接:https://ac.nowcoder.com/acm/contest/392/I 题目大意:一个含有n个顶点m条边的图,求经过所有顶点必须要经过的边数. 例: 输入: 5 51 22 33 ...

  2. 牛客寒假算法基础集训营4 F(二分+拓扑判环)

    题目链接 题目的输出:对于每次提问,输出一行"Yes"表示大家都遵守了群规,反之输出"No". 那么输出的就是一连串的yes和no了,二分一下无环的最大提问位置 ...

  3. 牛客网 牛客练习赛7 D. 珂朵莉的无向图(多源BFS)

    题目链接  Problem D 比赛的时候完全想不到 直接对给定的这些点做多源$BFS$,把给定的这些点全都压到队列里,然后一个个做. 最后统计被访问的点的个数即可. #include <bit ...

  4. 【并查集缩点+tarjan无向图求桥】Where are you @牛客练习赛32 D

    目录 [并查集缩点+tarjan无向图求桥]Where are you @牛客练习赛32 D PROBLEM SOLUTION CODE [并查集缩点+tarjan无向图求桥]Where are yo ...

  5. 牛客网 牛客练习赛43 C.Tachibana Kanade Loves Review-最小生成树(并查集+Kruskal)+建虚点+读入挂

    链接:https://ac.nowcoder.com/acm/contest/548/C来源:牛客网 Tachibana Kanade Loves Review 时间限制:C/C++ 2秒,其他语言4 ...

  6. 牛客练习赛43 Tachibana Kanade Loves Review C(最小生成树Kruskal)

    链接:https://ac.nowcoder.com/acm/contest/548/C来源:牛客网 题目描述 立华奏是一个刚刚开始学习 OI 的萌新. 最近,实力强大的 QingyuQingyu 当 ...

  7. Applese 的毒气炸弹 G 牛客寒假算法基础集训营4(图论+最小生成树)

    链接:https://ac.nowcoder.com/acm/contest/330/G来源:牛客网 Applese 的毒气炸弹 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262 ...

  8. 牛客练习赛32-D-MST+tarjin割边

    链接:https://ac.nowcoder.com/acm/contest/272/D来源:牛客网 题目描述 小p和他的朋友约定好去游乐场游玩,但是他们到了游乐场后却互相找不到对方了. 游乐场可以看 ...

  9. 牛客小白月赛12 I 华华和月月逛公园 (tarjian 求桥)

    链接:https://ac.nowcoder.com/acm/contest/392/I 来源:牛客网 华华和月月逛公园 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K, ...

随机推荐

  1. windows每天定时执行脚本

     windows每天定时执行脚本 这里说的定时器就是Windows下的任务计划,当时遇到的坑正好总结一下,因为Windows10的定时器去执行脚本当时试了好多遍,都是没有成功,后来通过自己的观察发现是 ...

  2. delphi基础篇之数据类型之一:1.简单类型(Simple)

    1.简单类型(Simple) 简单类型包括实数类型(Real)和有序类型(Ordinal).有序类型又包括整数类型.字符类型.布尔类型.枚举类型和子界类型等. 1-1.有序类型 有序类型是一个有序数的 ...

  3. SPSS聚类分析:K均值聚类分析

    SPSS聚类分析:K均值聚类分析 一.概念:(分析-分类-K均值聚类) 1.此过程使用可以处理大量个案的算法,根据选定的特征尝试对相对均一的个案组进行标识.不过,该算法要求您指定聚类的个数.如果知道, ...

  4. java程序中线程cpu使用率计算

    原文地址:https://www.imooc.com/article/27374 最近确实遇到题目上的刚需,也是花了一段时间来思考这个问题. cpu使用率如何计算 计算使用率在上学那会就经常算,不过往 ...

  5. LeetCode刷题笔记-DP算法-取数问题

    题目描述 (除数博弈论)爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需要执行以下操作: 选出任一 x,满足 0 < x < ...

  6. 微信1.8.6.1 SDK 无法授权登录解决办法

    我用的cocos2d-lua 3.9 项目打包 调用微信授权登录的时候 授权登录接口一直抛异常导致微信都无法拉起来 按照官网配置了universal link (这个也搞了很长时间jason 配置文件 ...

  7. CKEditor与CKFinder学习--自定义界面及按钮事件捕获

    原文地址:CKEditor与CKFinder学习--自定义界面及按钮事件捕获  讨厌CSDN的广告,吃香太难看! 效果图 界面操作图 原始界面 调整后的界面(删除了flush,表单元素等) 该界面的皮 ...

  8. 2018-10-31-WPF-在触摸线程等待主线程窗口关闭会让主线程和触摸线程相互等待

    title author date CreateTime categories WPF 在触摸线程等待主线程窗口关闭会让主线程和触摸线程相互等待 lindexi 2018-10-31 9:30:9 + ...

  9. Logstash详解之——filter模块-grok插件

    1. grok插件:能匹配一切数据,但是性能和对资源的损耗也很大. grok内置字段类型参见: https://blog.csdn.net/cui929434/article/details/9439 ...

  10. JS自运行函数的写法和MVVM框架数据驱动的底层逻辑

    1.JS自运行函数的写法 ( function(){ console.log(111)} )( ) !function(){ console.log(111) }() ( function(){}() ...