HDU 4612 Warm up —— (缩点 + 求树的直径)
题意:一个无向图,问建立一条新边以后桥的最小数量。
分析:缩点以后,找出新图的树的直径,将这两点连接即可。
但是题目有个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 —— (缩点 + 求树的直径)的更多相关文章
- 4612 warm up tarjan+bfs求树的直径(重边的强连通通分量)忘了写了,今天总结想起来了。
问加一条边,最少可以剩下几个桥. 先双连通分量缩点,形成一颗树,然后求树的直径,就是减少的桥. 本题要处理重边的情况. 如果本来就两条重边,不能算是桥. 还会爆栈,只能C++交,手动加栈了 别人都是用 ...
- F - Warm up - hdu 4612(缩点+求树的直径)
题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...
- HDU 4612 Warm up(双连通分量缩点+求树的直径)
思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v, ...
- hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径
题意如上,含有重边(重边的话,俩个点就能够构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v ...
- hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径
题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v ...
- (求树的直径)Warm up -- HDU -- 4612
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之 ...
- hdoj 4612 Warm up【双连通分量求桥&&缩点建新图求树的直径】
Warm up Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Su ...
- HDU 4612 Warm up (边双连通分量+缩点+树的直径)
<题目链接> 题目大意:给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量. 解题分析: 首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点 ...
- HDU 4612——Warm up——————【边双连通分量、树的直径】
Warm up Time Limit:5000MS Memory Limit:65535KB 64bit IO Format:%I64d & %I64u Submit Stat ...
随机推荐
- finally代码块的执行
try{ //todo }catch(Exception e){ //todo }finally{ //todo } 1.不管try,catch里面的代码快有无return,finally都会执行 2 ...
- springsecurity学习
首先讲一下,没有用到数据库,然后觉得重要的就是security的配置securityConfig.class,不太会说(好像也不太会用),上图吧,也是学习狂神过来的 项目结构 大致效果 pom.xml ...
- VisualStudio2015 安装
环境:Win10 64位 推荐安装顺序 IIS > Sqlserver > Asp.Net 启动安装程序(出现Logo后需要等待1到2分钟),选择安装路径(注意不要出现中文路径) 勾选需求 ...
- MSP432 BSL流程(UART)
升级流程 PC程序会解析脚本中的命令,根据命令码做相应的操作.数据来自于命令后的文件(当前目录下的数据文件) # cat script_P4xx_uart.txt LOG //记录日志 MODE P4 ...
- 【python+selenium】截取某个元素
一. selenium截图1.selenium提供了几个截取全屏的方法- get_screenshot_as_file(self, filename) --这个方法是获取当前window的截图,出现I ...
- shutil:高层文件操作
介绍 shutil模块包括一些高层文件操作,如赋值和归档 复制文件 import shutil ''' copyfile将源文件的内容复制到目标文件,如果没有权限写目标文件,则会产生一个IOError ...
- 如何制作 linux 系统 U盘启动盘
1.制作linux 系统的U盘启动盘,需要选择ISO 模式!给大家推荐几个制作相关软件以及相关制作过程(点击相应名字即可进入到网站):UltraISO.rufus.老毛桃.大白菜. UltraISO ...
- (十三)r18 cpu id
1.cpuid内核接口 lichee/linux-4.4/drivers/soc/sunxi/sunxi-sid.c int sunxi_get_soc_chipid(u8 *chipid) int ...
- 中国大学MOOC课程信息爬取与数据存储
版权声明:本文为博主原创文章,转载 请注明出处: https://blog.csdn.net/sc2079/article/details/82016583 10月18日更:MOOC课程信息D3.js ...
- java——多线程并发库
JDK5中增加了Doug Lea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性. java.util.current包中提供了对线程优化.管理的各项操作,使得线程的使用变得的心应手.该 ...