思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度。

  树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v,一定是直径的一个端点(证明从略),第二次以点v为开头进行bfs,求出的最后一个点,就是直径的另一个端点,记录深度就是我们要求的长度。我这里是使用的bfs+dfs,是一样的,少开一个deep数组,节省一下空间吧……

  其实我一开始是不会求的,我以为随便一个叶子节点就可以做端点,交上去WA,当时还好奇感觉没错,结果随便一画,就错了……

  注意:这个题里面有重边,我们可以通过重边走回父亲节点,但不可以通过父亲边回到父亲节点,所以原先标记父亲的方式是不可以的,这里改成标记边,在Edge结构体中多加一个vis的变量,标记这个边是否被访问过,那这样重边就能正常访问了。

  这个题的数据量比较强,容易爆栈,STL的实用性就不强了,所以尽量使用数组模拟,数组能够开到更大的空间。

  感想:感觉这一块的题目真心很爱出错,这个题真是WA了好多次才过的,感觉oj不爱我了……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define N 200020
#define M 2000020
struct Edge
{
int to,nxt,vis;
} edge[M];
int head[N],dfn[N],low[N],vis[N],sta[N],id[N];
int tot,all,top,scc,bridge;
void addedge(int a,int b,int flag)
{
edge[tot].to = b;
edge[tot].nxt = head[a];
edge[tot].vis = flag;
head[a] = tot++;
}
void tarjan(int u)
{
vis[u] = ;
dfn[u] = low[u] = ++all;
sta[top++] = u;
for(int i = head[u]; i != -; i = edge[i].nxt)
{
if(edge[i].vis) continue;
int v = edge[i].to;
edge[i].vis = edge[i^].vis = ;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u]) bridge++;
}
else if(vis[v]) low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u])
{
scc++;
int num;
do
{
num = sta[--top];
id[num] = scc;
vis[num] = ;
}
while(u != num);
}
}
vector<int> tree[N];
int treevis[N],maxdeep;
void dfs(int u,int deep)
{
treevis[u] = ;
maxdeep = max(deep,maxdeep);
int len = tree[u].size();
for(int i = ; i < len; i++)
{
int v = tree[u][i];
if(!treevis[v])
{
dfs(v,deep+);
}
}
}
void init()
{
memset(vis,,sizeof(vis));
memset(dfn,,sizeof(vis));
memset(id,,sizeof(id));
memset(low,,sizeof(low));
all = ;
top = ;
scc = ;
bridge = ;
}
int que[N];
int getstart()
{
int front,rear;
front = rear = ;
que[rear++] = ;
treevis[] = ;
while(front != rear)
{
int now = que[front++];
int len = tree[now].size();
for(int i = ; i < len; i++)
{
int nxt = tree[now][i];
if(treevis[nxt]) continue;
treevis[nxt] = ;
que[rear++] = nxt;
}
}
return que[--rear];
}
int main()
{
int n,m,a,b;
while(~scanf("%d%d",&n,&m))
{
if(!n && !m) break;
memset(head,-,sizeof(head));
tot = ;
for(int i = ; i < m; i++)
{
scanf("%d%d",&a,&b);
addedge(a,b,);
addedge(b,a,);
}
init();
tarjan();
for(int i = ; i <= scc; i++)
{
tree[i].clear();
}
for(int u = ; u <= n; u++)
{
for(int i = head[u]; i != -; i = edge[i].nxt)
{
int v = edge[i].to;
if(id[u] != id[v])
{
int uu = id[u];
int vv = id[v];
tree[uu].push_back(vv);
tree[vv].push_back(uu);
}
}
}
maxdeep = ;
memset(treevis,,sizeof(treevis));
int start = getstart();
memset(treevis,,sizeof(treevis));
dfs(start,);
printf("%d\n",scc-maxdeep);
}
return ;
}

HDU 4612 Warm up(双连通分量缩点+求树的直径)的更多相关文章

  1. 【HDOJ4612】【双连通分量缩点+找树的直径】

    http://acm.hdu.edu.cn/showproblem.php?pid=4612 Warm up Time Limit: 10000/5000 MS (Java/Others)    Me ...

  2. hdu 4612 Warm up 双连通缩点+树的直径

    首先双连通缩点建立新图(顺带求原图的总的桥数,事实上因为原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首 ...

  3. hdu 4612 Warm up 双连通+树形dp思想

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

  4. Codeforces 1000 组合数可行线段倒dp 边双联通缩点求树直径

    A /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std ...

  5. HDU 4005 The war 双连通分量 缩点

    题意: 有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值. 求敌人在最优的情况下,使图不连通的最小费用. 分析: 首先求出边双连通分量 ...

  6. hdu 4612 Warm up 有重边缩点+树的直径

    题目链接 Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Tot ...

  7. HDU 2460 Network 边双连通分量 缩点

    题意: 给出一个无向连通图,有\(m\)次操作,每次在\(u, v\)之间加一条边,并输出此时图中桥的个数. 分析: 先找出边双连通分量然后缩点得到一棵树,树上的每条边都输原图中的桥,因此此时桥的个数 ...

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

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

  9. HDU 4612 Warm up —— (缩点 + 求树的直径)

    题意:一个无向图,问建立一条新边以后桥的最小数量. 分析:缩点以后,找出新图的树的直径,将这两点连接即可. 但是题目有个note:两点之间可能有重边!而用普通的vector保存边的话,用v!=fa的话 ...

随机推荐

  1. 移动端日历控件 mobiscroll 的简单使用、参数设置

    mobiscroll 在性能方面比较好,可选用多种效果,滑动效果也比较顺畅.   提供样式文件和js文件,直接点击下载,该版本是 mobiscroll 2.13的 官方地址 :https://docs ...

  2. maven下载,安装与eclipse中maven配置

    1.maven下载.安装与环境变量配置 http://blog.csdn.net/jiuqiyuliang/article/details/45390313 2.Eclipse中maven的配置 ht ...

  3. 艰辛五天:Ubuntu14.04+显卡驱动+cuda+Theano环境安装过程

    题记:从一开始不知道显卡就是GPU(虽然是学计算机的,但是我真的不知道…脑残如我也是醉了),到搞好所有这些环境前后弄了5天时间,前面的买显卡.装显卡和装双系统见另一篇博客装显卡.双系统,这篇主要记录我 ...

  4. fragement生命周期

    转自http://www.cnblogs.com/mybkn/ 你的fragment们可以向activity的菜单(按Manu键时出现的东西)添加项,同时也可向动作栏(界面中顶部的那个区域)添加条目, ...

  5. python字符串中的中文处理

    python字符串中的字符串默认并非是unicode,如果在字符创中使用Unicode字符,如中文字符,必须要经过转换, 方式1: text = u"中文" 方式2: text = ...

  6. inflate的使用注意事项

    public View inflate (int resource, ViewGroup root, boolean attachToRoot) 我们在使用这个方法时,要清楚原理,下面是这个方法的文档 ...

  7. where条件的lambda转化为sql语句

    网上找的源码,但是博主说有bug 让自己调试.这个是我经过多次修改后的代码,可以直接用 public static class LambdaToSqlHelper { #region 基础方法 #re ...

  8. CSS3秘笈:第十章

    CSS的transform.transition和animation属性 1.transform(倾斜):利用transform属性可以使导航栏稍微倾斜,或者使图片在访问者的鼠标经过它时放大两倍,甚至 ...

  9. Java C# .net 和 C C++ 跨平台的区别

    当前主流的手机平台很多,而各个主流的平台的语言支持大同小异:如 1.windows系统WP8上主要支持 VB, C#, c/c++, 2.苹果系统ios上支持 object-c, c/c++ 3.an ...

  10. ASP.NET MVC View向Controller提交数据

    我们知道使用MVC的一个很重的的用途就是把Controller和View之间进行解耦,通过控制器来调用不同的视图,这就注定了Controller和View之间的传值是一个很重的知识点,这篇博文主要解释 ...