POJ 3177 边双连通求连通量度的问题
这道题的总体思路就是找到连通量让它能够看作一个集合,然后找这个集合的度,度数为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 边双连通求连通量度的问题的更多相关文章
- poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11047 Accepted: 4725 ...
- poj 3177 边双联通 **
题意:给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图. 链接:点我 kuangbin模板题,分析链接:点我 #include <stdio.h> #include < ...
- E - Redundant Paths - poj 3177(缩点求叶子节点)
题意:给一个图,想让每两个点之间都有两条路相连,不过特殊的是相同的两点之间多次相连被认为是一条边,现在求最少还需要添加几条边才能做到 分析:手欠没看清楚是相同的边只能相连一次,需要去重边,缩点后求出来 ...
- poj 3177 Redundant Paths
题目链接:http://poj.org/problem?id=3177 边双连通问题,与点双连通还是有区别的!!! 题意是给你一个图(本来是连通的),问你需要加多少边,使任意两点间,都有两条边不重复的 ...
- POJ 3177 Redundant Paths(边双连通的构造)
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13717 Accepted: 5824 ...
- tarjan算法求桥双连通分量 POJ 3177 Redundant Paths
POJ 3177 Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12598 Accept ...
- POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)
POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的.一份代码能交.给定一个连通无向图,问加几条边能使得图变成一个双连通图 ...
- POJ 3177——Redundant Paths——————【加边形成边双连通图】
Redundant Paths Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Sub ...
- DFS入门之二---DFS求连通块
用DFS求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所 ...
随机推荐
- 伟景行 citymaker 从入门到精通系列
伟景行 citymaker 从入门到精通(1)——js开发,最基本demo,加载cep工程文件 伟景行 citymaker 从入门到精通(2)——工程图层树加载 伟景行 citymaker 从入门 ...
- How to proxy a web site by apache2 in Ubuntu
Install apache2 To execute the install command in terminal: sudo apt-get install apache2 Then, we ca ...
- 【HEVC简介】ALF-Adative Loop Filter
由于HEVC在HM4.0之后,就把ALF去掉,所以ALF的介绍是基于AVS2. <HEVC标准介绍.HEVC帧间预测论文笔记>系列博客,目录见:http://www.cnblogs.com ...
- SQLite -附加数据库
SQLite -附加数据库 考虑情况下当你有多个数据库可用,您希望使用其中任何一个.SQLite附加DTABASE语句用于选择一个特定的数据库,这个命令之后,所有SQLite语句将执行以下附加数据库. ...
- html自己写响应式布局(说起来很高大上的样子,但是其实很简单)
第一步,打开电脑中安装的Sublime Text3,新建demo文件夹用来存放文件,在里面新建一个HTML文件,通过Tab快捷键迅速创建一个HTML模板,并命名标题. 第二步,在Body标签里添加三个 ...
- mount nfs 各版本之间的转换
[root@one1-fst-hx ~]# mount.nfs 182.168.2.49:/mnt/sdb/nfs /mnt/nfs2/ nomand,-o vers=3[root@one1-fst- ...
- libs/tools.js stringToDate dateToString 日期字符串转换函数
libs/tools.js stringToDate dateToString 日期字符串转换函数 import { stringToDate } from '@/libs/tools.js' e ...
- 检查bug
用selective_search生成的坐标是(ymin,xmin,ymax,xmax),并且是从1开始的,不是从0 这是cache中的gt数据,明显看到有65535,说明很有可能是0-1变成了655 ...
- Perl 安装 JSON 包
$tar xvfz JSON.tar.gz $cd JSON $perl Makefile.PL $make $make install
- win10 配置系统默认utf-8编码
win10 配置系统默认utf-8编码 系统 win10 配置系统默认utf-8编码 Windows系统默认字符编码为gbk编码,开发项目编码一般为UTF-8,在我们执行程序及进行程序编码过程中编码 ...