POJ 3177 边双连通求连通量度的问题

时间:2022-08-31 18:47:51

这道题的总体思路就是找到连通量让它能够看作一个集合,然后找这个集合的度,度数为1的连通量为k,那么需要添加(k+1)/2条边才可以保证边双连通

这里因为一个连通量中low[]大小是相同的,所以我们用ans[low[i]]++来计度数

这道题我最开始按学长的模板来写。。。。MLE到哭了,也不知道这道题为什么这么逗,把5000的数组改成1000也能过,当然后来换了别的思路

为了防止重边的进入,开始设置了一个hash[][]二维数组来判断边是否已经存在,不额外添入

之后,我不采用二维数组,而是在get_bcc函数中利用visit[]一维数组来防止重边的多次访问,也就是说我允许添入多个边,但我不让它多次被访问

这样每循环一次,我就需要更新一次数组,但是空间耗费少了特别多还是很好的。

自己修改多次的代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define N 5005
int k,n,first[N],tmpdfn,dfn[N],low[N],cnt;//isBridge[][]用来判断是否为桥,cnt记载桥的个数 struct Path{
int y,next;
}path[*N];
void add(int x,int y)
{
path[k].y=y,path[k].next=first[x];
first[x]=k;
k++;
}
void dfs(int u,int fa)
{
dfn[u]=low[u]=++tmpdfn;
for(int i=first[u];i!=-;i=path[i].next){
int v=path[i].y;
if(!dfn[v]){
dfs(v,u);
low[u]=min(low[u],low[v]);
}
else if(v!=fa)
low[u]=min(low[u],dfn[v]);
}
} void get_bcc(int n)
{
int visit[N]; cnt=;
int ans[N];
memset(ans,,sizeof(ans));
for(int i=;i<=n;i++){
if(!dfn[i]) dfs(n,-);
}
for(int i=;i<=n;i++){
memset(visit,,sizeof(visit));
for(int j=first[i];j!=-;j=path[j].next){
int v=path[j].y;
if(low[i]!=low[v]&&!visit[v])
ans[low[i]]++,visit[v]=; }
}
for(int i=;i<=n;i++)
if(ans[i]==) cnt++;
}
int main()
{
int R,x,y;
while(scanf("%d%d",&n,&R)!=EOF){ tmpdfn=,k=;
memset(dfn,,sizeof(dfn));
memset(first,-,sizeof(first)); for(int i=;i<R;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x); }
get_bcc(n); printf("%d\n",(cnt+)/);
}
return ;
}

学长的代码,作为模版还是很有价值的:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define maxn 1010
using namespace std; int pre[maxn],dfs_clock,isbridge[maxn][maxn];
vector<int> G[maxn];
bool hash[maxn][maxn]; int dfs1(int u,int fa){
int lowu = pre[u] = ++dfs_clock;
for(int i = ;i < G[u].size();i++){
int v = G[u][i];
if(!pre[v]){
int lowv = dfs1(v,u);
lowu = min(lowu,lowv);
if(lowv > pre[u]){
isbridge[u][v] = isbridge[v][u] = ;
}
}else if(pre[v] < pre[u] && v != fa){
lowu = min(lowu,pre[v]);
}
}
return lowu;
} int fa[maxn],vis[maxn];
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);} void dfs2(int u){
for(int i = ;i < G[u].size();i++){
int v = G[u][i];
if(!vis[v] && !isbridge[u][v]){
int x = find(u);int y = find(v);
if(x != y) fa[x] = y;
vis[v] = ;
dfs2(v);
}
}
} void find_bcc(int n){
memset(pre,,sizeof(pre));
memset(isbridge,,sizeof(isbridge));
dfs_clock = ;
for(int i = ;i < n;i++)
if(!pre[i]) dfs1(i,-);
for(int i = ;i < n;i++){
if(!vis[i]){
vis[i] = ;
dfs2(i);
}
}
} int degree[maxn];
bool used[maxn]; int main()
{
int n,m;
while(scanf("%d%d",&n,&m) == ){
for(int i = ;i < n;i++){
fa[i] = i;
G[i].clear();
}
memset(hash,,sizeof(hash));
for(int i = ;i < m;i++){
int a,b;
scanf("%d%d",&a,&b);
a--;b--;
if(!hash[a][b]){
G[a].push_back(b);
G[b].push_back(a);
hash[a][b] = hash[b][a] = ;
}
} find_bcc(n); memset(degree,,sizeof(degree));
memset(used,,sizeof(used)); for(int i = ;i < n;i++)
for(int j = ;j < G[i].size();j++){
if(find(i) != find(G[i][j]))
degree[find(G[i][j])]++;
} int sum = ;
for(int i = ;i < n;i++){
int x = find(i);
if(!used[x]){
used[x] = ;
if(degree[x] == ) sum++;
else if(degree[x] == ) sum += ;
}
} int cnt = ;
for(int i = ;i < n;i++){
if(used[i] == ) cnt++;
} if(cnt == ) printf("0\n");
else printf("%d\n",(sum+)/); }
return ;
}

POJ 3177 边双连通求连通量度的问题的更多相关文章

  1. poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11047   Accepted: 4725 ...

  2. poj 3177 边双联通 &ast;&ast;

    题意:给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图. 链接:点我 kuangbin模板题,分析链接:点我 #include <stdio.h> #include < ...

  3. E - Redundant Paths - poj 3177(缩点求叶子节点)

    题意:给一个图,想让每两个点之间都有两条路相连,不过特殊的是相同的两点之间多次相连被认为是一条边,现在求最少还需要添加几条边才能做到 分析:手欠没看清楚是相同的边只能相连一次,需要去重边,缩点后求出来 ...

  4. poj 3177 Redundant Paths

    题目链接:http://poj.org/problem?id=3177 边双连通问题,与点双连通还是有区别的!!! 题意是给你一个图(本来是连通的),问你需要加多少边,使任意两点间,都有两条边不重复的 ...

  5. POJ 3177 Redundant Paths(边双连通的构造)

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13717   Accepted: 5824 ...

  6. tarjan算法求桥双连通分量 POJ 3177 Redundant Paths

    POJ 3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12598   Accept ...

  7. POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)

    POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的.一份代码能交.给定一个连通无向图,问加几条边能使得图变成一个双连通图 ...

  8. POJ 3177——Redundant Paths——————【加边形成边双连通图】

    Redundant Paths Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Sub ...

  9. DFS入门之二---DFS求连通块

    用DFS求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所 ...

随机推荐

  1. Linux C&plus;&plus; 开发简介

    主要介绍将Windows程序迁移到Linux系统相关知识 简介 Windows程序迁移到Linux系统可能需要修改很多代码, 既需要了解Linux平台的开发知识, 也需要了解Windows平台代码如何 ...

  2. Linux中检索文件

    1 , Use locate command It is a fast way to find the files location, but if a file just created ,it w ...

  3. iOS应用之间跳转

    本篇博文将涉及到以下知识点: app应用跳转的原理解析 如何实现两个app应用之间的跳转 如何实现两个app之间跳转到指定界面 二.应用跳转原理 相信从一个应用跳转到另一个应用大家并不陌生,最常见的莫 ...

  4. CoreData 基本操作方法封装

    转:http://blog.csdn.net/marujunyy/article/details/18500523 为了方便使用CoreData 封装了几个扩展类,使用方法和类文件如下: //首先需要 ...

  5. Java &lbrack;leetcode 20&rsqb;Valid Parentheses

    题目描述: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if th ...

  6. Linux程序设计 读笔1

    第一章 入门 Linux应用程表现为两种特殊类型文件:可执行文件 + 脚本文件 /bin 二进制文件目录,存放启动系统时用到的标准程序 /usr/bin 用户二进制文件目录,存放用户使用的标准程序 / ...

  7. cpp智能指针

    weak_ptr<Cls1> wp1; { shared_ptr<Cls1> ptr1(new Cls1);//共享指针 wp1 = ptr1;//临时共享指针 std::co ...

  8. mac配置自带vim高亮显示

    查找/etc/.vimrc的内容,如果没有的话 新建~/vimrc文件,在文件中写入如下内容即可 set ai " auto indenting set history=100 " ...

  9. VMware下liunx虚拟机仅主机模式上网

    VMware上的配置 虚拟网络编辑器上的仅主机模式设置 可以自定义虚拟机的网段,我设置的是192.168.137.0 选择对应网卡的联网方式为仅主机模式 配置虚拟机网卡,主要是按虚拟网卡编辑器中设置的 ...

  10. 涂抹mysql笔记-搭建mysql高可用体系

    mysql的高可用体系<>追求更高稳定性的服务体系 可扩展性:横向扩展(增加节点).纵向扩展(增加节点的硬件配置) 高可用性<>Slave+LVS+Keepalived实现高可 ...