题意:一个无向图,问建立一条新边以后桥的最小数量。

  分析:缩点以后,找出新图的树的直径,将这两点连接即可。

  但是题目有个note:两点之间可能有重边!而用普通的vector保存边的话,用v!=fa的话是没办法让重边访问的,因此,使用数组模拟邻接表的方法来储存边。

这样,只要访问了一条边以后,令E[i].vis=E[i^1].vis=1即可,这样可以防止无向图的边和重边搞混。原理就是按位异或,一个奇数^1变为比它小1的偶数,反之亦然:如5^1=4,4^1=5。

  具体见代码:

 #include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <vector>
#include <set>
#include <queue>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; const int N = +; int n,m,dfn[N],low[N];
int head[N];
int tot=;
int dfs_clock;
int bridge;
int belong[N];
int scc_cnt;
int maxd;
bool vis[N];
vector<int> G[N];
stack<int> S; struct edge
{
int v;
int vis;
int nxt;
}E[*+]; void addEdge(int u,int v)
{
E[tot].v=v;
E[tot].vis=;
E[tot].nxt=head[u];
head[u]=tot++; E[tot].v=u;
E[tot].vis=;
E[tot].nxt=head[v];
head[v]=tot++;
} void tarjan(int u)
{
dfn[u]=low[u]=++dfs_clock;
S.push(u);
for(int i=head[u];i!=-;i=E[i].nxt)
{
int v = E[i].v;
if(E[i].vis) continue;
E[i].vis=E[i^].vis=; if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) bridge++;
}
else if(!belong[v])
{
low[u]=min(low[u],dfn[v]);
}
} if(dfn[u]==low[u])
{
scc_cnt++;
for(;;)
{
int x = S.top();S.pop();
belong[x] = scc_cnt;
if(x==u) break;
}
}
} void init()
{
memset(head,-,sizeof(head));
tot=;
memset(dfn,,sizeof(dfn));
dfs_clock=;
bridge=;
memset(belong,,sizeof(belong));
scc_cnt=;
maxd=;
for(int i=;i<=n;i++) G[i].clear();
memset(vis,,sizeof(vis));
} //找到树的直径
void findMaxDeep(int u,int deep)
{
vis[u]=; maxd=max(maxd,deep);
for(int i=;i<G[u].size();i++)
{
int v = G[u][i];
if(!vis[v])
{
findMaxDeep(v,deep+);
}
}
} //用bfs来找到一个叶子节点
int findRoot()
{
queue<int> Q;
Q.push();
vis[]=;
int last=;
while(!Q.empty())
{
int x = Q.front();Q.pop();
for(int i=;i<G[x].size();i++)
{
int v = G[x][i];
if(!vis[v])
{
Q.push(v);
vis[v]=;
last=v;
}
}
}
return last;
} void solve()
{
for(int i=;i<=n;i++) if(!dfn[i]) tarjan(i); //重新建图
for(int i=;i<=n;i++)
{
for(int j=head[i];j!=-;j=E[j].nxt)
{
int v = E[j].v;
int x = belong[i];
int y = belong[v];
if(x!=y)
{
G[x].push_back(y);
G[y].push_back(x);
}
}
} int root=findRoot();
memset(vis,,sizeof(vis)); findMaxDeep(root,); printf("%d\n",bridge-maxd);
} int main()
{
while(scanf("%d%d",&n,&m)==)
{
if(n== && m==) break;
init(); for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
} solve();
}
}

  但是奇怪的是,重新建图以后找叶子节点的时候,这里用G[x].size()==2不能够实现。讲道理,原理上是没错的,尽管后来发现如果缩点后只有一个点的话是个例外,但是即使排除了这个特殊情况仍然不行,,,这个问题也留着以后探讨吧。。

HDU 4612 Warm up —— (缩点 + 求树的直径)的更多相关文章

  1. 4612 warm up tarjan+bfs求树的直径(重边的强连通通分量)忘了写了,今天总结想起来了。

    问加一条边,最少可以剩下几个桥. 先双连通分量缩点,形成一颗树,然后求树的直径,就是减少的桥. 本题要处理重边的情况. 如果本来就两条重边,不能算是桥. 还会爆栈,只能C++交,手动加栈了 别人都是用 ...

  2. F - Warm up - hdu 4612(缩点+求树的直径)

    题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...

  3. HDU 4612 Warm up(双连通分量缩点+求树的直径)

    思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v, ...

  4. hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径

    题意如上,含有重边(重边的话,俩个点就能够构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v ...

  5. hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

    题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v ...

  6. (求树的直径)Warm up -- HDU -- 4612

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之 ...

  7. hdoj 4612 Warm up【双连通分量求桥&&缩点建新图求树的直径】

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

  8. HDU 4612 Warm up (边双连通分量+缩点+树的直径)

    <题目链接> 题目大意:给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量. 解题分析: 首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点 ...

  9. HDU 4612——Warm up——————【边双连通分量、树的直径】

    Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Stat ...

随机推荐

  1. oracle用户解锁,rename管理

    ---查看命令:用户默认表空间 SYS@ACE >select username,default_tablespace,temporary_tablespace,created from dba ...

  2. 怎样理解第三方Cookie

    1. Cookie往往是用来存储用户信息的, 但有些恶意站点设法伪造了带有正确Cookie的HTTP请求, 这时就会产生安全问题( CSRF 攻击 ). 这里恶意网站获取cookie的行为就是第三方c ...

  3. 浅谈后缀数组SA

    这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的. 给你们分享了那么多,容我自私一回吧~ 参考资料:这位dalao的blog 一.关于求Suffix ...

  4. SQL Prompt 注册后隔一段时间莫名无法使用的处理

    https://blog.csdn.net/anyqu/article/details/88537197 以前一直以为是授权丢了,反复重装也解决不了 Sql Prompt---Unable to co ...

  5. C# 使用Emit实现动态AOP框架 (一)

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

  6. 史上最全Java集合中List,Set以及Map等集合体系详解

    一.概述 List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有HashSet,LinkedHashSet,TreeSet List下有ArrayL ...

  7. LeetCode 腾讯精选50题--链表排序

    解题思路:归并 先把链表拆开,分为两部分,一直拆到只剩一个元素后,进行合并,利用一个临时节点记录重排后的链表的起始位置 合并不难,困难点在于如何拆分链表,自己的大体思路是利用两个指针,一个一次移动两位 ...

  8. 【php设计模式】责任链模式

    责任链模式为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式. 在这种模式中,通常每个接收者都包含对另一个接收者的引用.如果一个对 ...

  9. LeetCode:180.连续出现的数字

    题目链接:https://leetcode-cn.com/problems/consecutive-numbers/ 题目 编写一个 SQL 查询,查找所有至少连续出现三次的数字. +----+--- ...

  10. android项目笔记整理(3)

    61.AlphabetIndexer字母索引辅助类       实现对链表类型的数据进行快速索引. 应用于类似联系人列表右侧的导航栏 注意:       1.链表里的元素必须是Object类型,并实现 ...