HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)
/** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求最长链,连接首尾即可;剩下的连通块即为所求答案; 算法思路: 对图深度优先搜索,定义DFN(u)为u在搜索树中被遍历到的次序号; 定义Low(u)为u或u的子树中能通过非父子边追溯到的最早的节点,即DFN序号最小的节点; 则有: Low(u)=Min { DFN(u), Low(v),(u,v)为树枝边,u为v的父节点 DFN(v),(u,v)为指向栈中节点的后向边(非横叉边) } 一个顶点u是割点,当且仅当满足(1)或(2) (1)u为树根,且u有多于一个子树; (2)u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFN(u)<=Low(v); 一条无向边(u,v)是桥,当且仅当(u,v)为树枝边且满足DFN(u)<Low(v); **/ #pragma comment(linker,"/STACK:102400000,102400000") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<stack> using namespace std; const int N=200010; const int M=1000010; struct node { int v; int next; } e[M*2]; int head[N]; int dfn[N],low[N],dp[N][2];//dp[i][0]表示第i个节点的子树中最长的链,dp[i][1]表示第i个节点的子树中第二长的链 bool visit[M]; int n,m,cnt,res; void AddEdge(int u,int v) { e[cnt].v=v; e[cnt].next=head[u]; head[u]=cnt++; } void Tarjan(int u) { dfn[u]=low[u]=cnt++; dp[u][0]=dp[u][1]=0; for(int i=head[u]; i!=-1; i=e[i].next) { int j=e[i].v; if(!visit[i>>1]) { visit[i>>1]=true; if(dfn[j]==0)//跟强连通一样 { Tarjan(j); res+=dfn[u]<low[j];//统计连通块,比实际数目少一个,就是回溯的时候的最后一个 int temp=dp[j][0]+(dfn[u]<low[j]); if(temp>dp[u][0]) { dp[u][1]=dp[u][0]; dp[u][0]=temp; } else if(temp>dp[u][1]) { dp[u][1]=temp; } low[u]=min(low[u],low[j]); } else low[u]=min(low[u],dfn[j]); } } } int main() { #ifndef ONLINE_JUDGE freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin); #endif while(scanf("%d%d",&n,&m)&&n+m) { cnt=0; res=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(head,-1,sizeof(head)); for(int i=0; i<m; i++) { int u,v; scanf("%d%d",&u,&v); AddEdge(u,v); AddEdge(v,u); } cnt=1; memset(visit,0,sizeof(visit)); Tarjan(1); int temp=0; for(int i=1; i<=n; i++) { temp=max(temp,dp[i][0]+dp[i][1]);//+的时候没有算当前点所在的块,但是res也少算一个 } printf("%d\n",res-temp); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)