Warm up——缩点树上直径
Posted j666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Warm up——缩点树上直径相关的知识,希望对你有一定的参考价值。
题意:
给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。
题解:
把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),
然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。
因为如果我们把直径所在的两个端点连起来,这样减少的桥最多。
所以 答案就是 桥的数量 - 树的直径上桥的数量
原图求桥的数量,缩点后建立新的图求直径
代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <queue> using namespace std; const int maxn = 200005;//点数 const int maxm = 2001000;//边数,因为是无向图,所以这个值要*2 struct Edge { int to,next; bool cut;//是否是桥标记 } edge[maxm],edge1[maxm]; int head[maxn],tot,head1[maxn],tot1; int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];//belong数组的值是1~scc int Index,top; int scc;//边双连通块数/强连通分量的个数 bool Instack[maxn]; int bridge;//桥的数目 bool cut[maxn]; void addedge(int u,int v) { edge[tot].to = v; edge[tot].next = head[u]; edge[tot].cut=false; head[u] = tot++; } void add(int u,int v) { edge1[tot1].to = v; edge1[tot1].next = head1[u]; head1[u] = tot1++; } void Tarjan(int u,int pre) { int v; low[u] = dfn[u] = ++Index; Stack[top++] = u; Instack[u] = true; int son=0; int flag=0; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(v == pre && !flag) { flag++; continue; } if( !dfn[v] ) { son++; Tarjan(v,u); if( low[u] > low[v] )low[u] = low[v]; if(low[v] > dfn[u]) { bridge++; edge[i].cut = true; edge[i^1].cut = true; } if(u == pre && son > 1)cut[u] = true; if(u != pre && low[v] >= dfn[u])cut[u] = true; } else if( Instack[v] && low[u] > dfn[v] ) low[u] = dfn[v]; } if(low[u] == dfn[u]) { scc++; do { v = Stack[--top]; Instack[v] = false; belong[v] = scc; } while( v!=u ); } } void init() { tot = 0; memset(head,-1,sizeof(head)); } void init1() { tot1 = 0; memset(head1,-1,sizeof(head1)); } int deep[maxn]; int bfs(int s) { queue<int> Q; memset(deep,0,sizeof deep); deep[s] = 1; Q.push(s); int ans = s; while(!Q.empty()) { int u = ans = Q.front(); Q.pop(); for(int i=head1[u]; ~i; i=edge1[i].next)if(!deep[edge1[i].to]) { int v=edge1[i].to; deep[v] = deep[u]+1; Q.push(v); } } return ans; } void solve(int n) { memset(dfn,0,sizeof(dfn)); memset(Instack,false,sizeof(Instack)); memset(cut,0,sizeof cut); Index = top = scc = 0; bridge = 0; for(int i = 1; i <= n; i++) if(!dfn[i]) Tarjan(i,i); init1(); for(int i=1; i<=n; i++) { for(int j=head[i]; ~j; j=edge[j].next) { int u=belong[i]; int v=belong[edge[j].to]; if(u!=v) { add(u,v); add(v,u); } } } int ans=deep[bfs(bfs(1))]; printf("%d ",scc-1-(ans-1)); } int main() { int n,m; while(~scanf("%d%d",&n,&m) && (n || m)) { init(); while(m--) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } solve(n); } return 0; } /* 4 4 1 2 1 3 1 4 2 3 0 0 */
以上是关于Warm up——缩点树上直径的主要内容,如果未能解决你的问题,请参考以下文章
HDU 4612 Warm up(双连通分量缩点+求树的直径)
HDU 4612 Warm up —— (缩点 + 求树的直径)