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求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所 ...
随机推荐
- asp.net 线程批量导入数据,ajax获取执行状态
最近做了一个批量导入功能,长时间运行,没个反馈状态,很容易让人看了心急,产生各种臆想!为了解决心里障碍,写了这么个功能. 通过线程执行导入,并把正在执行的状态存入session,既共享执行状态,通过a ...
- [转]Android APK签名原理及方法
准备知识:数据摘要 这个知识点很好理解,百度百科即可,其实他也是一种算法,就是对一个数据源进行一个算法之后得到一个摘要,也叫作数据指纹,不同的数据源,数据指纹肯定不一样,就和人一样. 消息摘要算法(M ...
- 2. UITest相关APIs
1. XCUIApplication 这是你正在测试的应用的代理.它能让你启动应用,这样你就能执行测试了.它每次都会新起一个进程,这会多花一些时间,但是能保证测试应用时的状态是干净的,这样你需要处理的 ...
- obj.style 和currentstyle 等区别
版权声明:本文为博主原创文章,未经博主允许不得转载. 获取样式 obj.style 和currentstyle 等区别 obj.style只能获得内嵌样式(inline Style)就是写 ...
- Java垃圾回收机制分析
Java的堆是一个运行时数据区,类的实例从中分配空间,堆中存储着正在运行的应用程序所建立的所有对象.垃圾回收是一种动态存储管理技术.它按照特定的垃圾回收算法,自动释放掉不再被引用的对象.堆内存里垃圾的 ...
- 使用Jenkins进行android项目的自动构建(6)
之前已经介绍过使用Maven做构建,在来介绍一下Gralde的自动化构建. 什么是Gralde?官方的解释是 Gradle is an open source build automation sys ...
- Linux之vi(vim)编辑器
命令行模式:默认进来就是命令行模式 ,可以使用很多命令:比如i . a . o i:光标前面输入内容 a:光标的下一位字符开始输入内容 o:光标的下一行开始输入内容 编辑模式: 退出编辑模式:键盘上e ...
- python_使用qrcode生成二维码
1.功能 使用qrcode生成二维码 2.代码 #生成二维码: import qrcode #根据url生成二维码 def qrcodeWithUrl(url): img = qrcode.make( ...
- 字符串KMP || POJ 2185 Milking Grid
求一个最小矩阵,经过复制能够覆盖原矩阵(覆盖,不是填充,复制之后可以有多的) *解法:横着竖着kmp,求最大公倍数的做法是不对的,见http://blog.sina.com.cn/s/blog_69c ...
- Java中Synchronized和Lock的使用
Lock的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的 synchronized在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线 ...