POJ - 3352 无向图的割和桥以及双连通分量

本文详细介绍了无向图中桥与割点的概念,并阐述了由Tarjan发明的算法如何寻找这些元素。进一步探讨了如何使用此算法解决特定问题,例如将无向图转变为双连通图所需的最少边数。

双连通分量是指图中每两个点都有两条完全不同的路径可到达..也就是去掉这个图的任意一个边一个点...两两之间依然可达..

图论中的桥...在有向图中是两个连通分量之间唯一的边(如果有多条那么都不是桥)...在无向图中是两个双连通分量之间的唯一边...

而割指的是割点..割点肯定是和桥的端点...但桥的端点不一是割点..如:


(1,4),(2,4),(3,4),(4,5),(4,6),(4,7)都是桥..所有点都是桥的端点...但是只有4是割点...1,2,3,5,6,7都不是割点..

去掉一个连通图中的一个桥或者割点..这个连通图就将成为不连通的多个连通图..

求无向图中的桥的方法是有Tarjan发明的..Byvoid大大的讲解很给力:http://www.byvoid.com/blog/biconnect/

无向图的Tarjan和有向图求强连通分量的Tarjan很像...注意几个不同...

1、没有栈..所以判断时先是看点有没有访问过...else的时候就直接更新Low...不需要再来个判断instack....

2、DFS时不能从 a 递归到了 b..b又马上从a来更新...所以要多加一个notpre..代表递归b时是从哪个点进去的...防止这种情况..

3、Low相等的点在无向图中就是在一个双连通图中...这个比有向图的方便..有向图还需要用栈来维护..通过判断退栈来判断强连通分量..

如果要求桥和割点的话..做完Tarjan..扫描所有的边,有 DFN ( 终点 ) < LOW ( 起点 ) 的边就是桥...这条边的"终点"就是割点..

回到POJ3352...题目给出了连通的无向图..并且两点直接最多只有一条边...求的是加几条边能使得该无向图整个变成一个双连通图..

那么先对图做无向图的Tarjan...得到每个点所在的双连通记录在Low里....可以想象一下..如果把所有的双连通分量分别缩成一个点...那么整个图就是一棵树了..如果给一棵树..要史其成为一个双连通图...那么需要加( 叶子结点数+1)/2调边...

这道题就是在做完Tarjan找作为叶子节点的双连通分量的个数k..然后答案就是(k+1)/2...

Program:

// POJ3352 加边做双连通图 #include<iostream> #include<stack> #include<math.h> #define MAXN 5001 using namespace std; struct pp { int x,y,next; }line[MAXN*5]; int n,m,link[MAXN],i,p,low[MAXN],dfn[MAXN],tp[MAXN],numtp,sum[MAXN]; bool instack[MAXN],used[MAXN]; stack<int> mystack; void trajin(int h) { int k; instack[h]=true; mystack.push(h); low[h]=dfn[h]=++p; k=link[h]; while (k) { if (!dfn[line[k].y]) { trajin(line[k].y); low[h]=min(low[h],low[line[k].y]); }else if (instack[line[k].y]) { low[h]=min(low[h],dfn[line[k].y]); } k=line[k].next; } k=h; if (low[k]==dfn[k]) { numtp++; do { k=mystack.top(); tp[k]=numtp; mystack.pop(); instack[k]=false; }while ( low[k]!=dfn[k]); } return; } void getanswer() { int i; memset(instack,false,sizeof(instack)); while (!mystack.empty()) mystack.pop(); memset(tp,0,sizeof(tp)); memset(dfn,0,sizeof(dfn)); p=0; numtp=0; for (i=1;i<=n;i++) if (!dfn[i]) trajin(i); for (i=1;i<=n;i++) if (!tp[i]) { printf("\n"); return; } memset(link,0,sizeof(link)); memset(sum,0,sizeof(sum)); for (i=1;i<=m;i++) if (tp[line[i].x]!=tp[line[i].y]) { p++; sum[tp[line[i].x]]++; } for (i=1;i<=n;i++) if (!sum[tp[i]]) printf("%d ",i); printf("\n"); return; } int main() { while (~scanf("%d%",&n)) { if (!n) break; scanf("%d",&m); memset(link,0,sizeof(link)); memset(line,0,sizeof(line)); for (i=1;i<=m;i++) { scanf("%d%d",&line[i].x,&line[i].y); line[i].next=link[line[i].x]; link[line[i].x]=i; } getanswer(); } return 0; }



 
 
内容概要:本文介绍了一套针对智能穿戴设备的跑步/骑行轨迹记录系统实战方案,旨在解决传统运动APP存在的定位漂移、数据断层路径分析单一等问题。系统基于北斗+GPS双模定位、惯性测量单元(IMU)海拔传感器,实现高精度轨迹采集,并通过卡尔曼滤波算法修正定位误差,在信号弱环境下利用惯性导航补位,确保轨迹连续性。系统支持跑步与骑行两种场景的差异化功能,包括实时轨迹记录、多维度路径分析(如配速、坡度、能耗)、数据可视化(地图标注、曲线图、3D回放)、异常提醒及智能优化建议,并可通过蓝牙/Wi-Fi同步数据至手机APP,支持社交分享与专业软件导出。技术架构涵盖硬件层、设备端与手机端软件层以及云端数据存储,强调低功耗设计与用户体验优化。经过实测验证,系统在定位精度、续航能力场景识别准确率方面均达到预期指标,具备良好的实用性扩展性。; 适合人群:具备一定嵌入式开发或移动应用开发经验,熟悉物联网、传感器融合与数据可视化的技术人员,尤其是从事智能穿戴设备、运动健康类产品研发的工程师产品经理;也适合高校相关专业学生作为项目实践参考。; 使用场景及目标:① 开发高精度运动轨迹记录功能,解决GPS漂移与断点问题;② 实现跑步与骑行场景下的差异化数据分析与个性化反馈;③ 构建完整的“终端采集-手机展示-云端存储”系统闭环,支持社交互动与商业拓展;④ 掌握低功耗优化、多源数据融合、动态功耗调节等关键技术在穿戴设备中的落地应用。; 阅读建议:此资源以真实项目为导向,不仅提供详细的技术实现路径,还包含硬件选型、测试验证与商业扩展思路,建议读者结合自身开发环境,逐步实现各模块功能,重点关注定位优化算法、功耗控制策略与跨平台数据同步机制的设计与调优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值