图论 —— 图的连通性 —— 有桥连通图加边变边双连通图
对于一个有桥的连通图,加边变成边双连通图
1.求出所有的桥,然后删除这些桥边。剩下的每个连通块都是一个双连通子图。
2.把每个双连通子图收缩为一个顶点。
3.加回桥边,统计度为1的节点的个数(叶节点的个数),记为 leaf
则:至少在树上加 (leaf+1)/2 条边,就能使树达到边双连通
除使用两次 dfs 外,还可以使用 Tarjan 算法一次求出所有点的 low[i] 值,由于同一个边双连通分量的点他们的 low[i] 值一定相同,因此对于不同边双连通分量的点,他们的 low 值一定不同。
int n,m;
int dfn[N],low[N];
int degree[N];
int block_cnt;
vector<int> G[N];
int Tarjan(int x,int father) {
int lowx=dfn[x]=++block_cnt;
for(int i=0; i<G[x].size(); i++) {
int y=G[x][i];
if(y==father)
continue;
if(dfn[y]==0) {
int lowy=Tarjan(y,x);
lowx=min(lowx,lowy);
} else if(dfn[y]<dfn[x])
lowx=min(lowx,dfn[y]);
}
return low[x]=lowx;
}
int main() {
scanf("%d%d",&n,&m);
block_cnt=0;
memset(dfn,0,sizeof(dfn));
memset(degree,0,sizeof(degree));
for(int i=0; i<n; i++)
G[i].clear();
for(int i=1; i<=m; i++) {
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
Tarjan(1,-1);//求所有点的low值
for(int x=1; x<=n; x++) { //遍历每条边
for(int i=0; i<G[x].size(); i++) {
int y=G[x][i];
if(low[x]!=low[y])//每个不同的low值代表一个边双连通分量
degree[low[y]]++;
}
}
int cnt=0;
for(int i=1; i<=n; i++)
if(degree[i]==1)
cnt++;
printf("%d\n",(cnt+1)/2);//加边条数
/*
* 边双连通分量个数
* int cnt=0;
* for(int i=1;i<=n;i++)
* if(degree[i]>0)
* cnt++;
* printf("%d\n",cnt);
*/
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】