HDU 3394 Railway(点双连通分量的应用)

题意:给定一个无向图,分别求出不在任何环中的边的数量和同时在两个或以上的环中的边的数量。

解法:桥上的边就是不在任何环中的。而如果一个点双连通分量中边的数量比点的数量要多,那么该双连通分量的所有边都同时在两个或以上的环中(这个可以想象一下,在一个简单环中多加一条端点不同的边,这样简单环就会被分割成两个小的简单环,任何一条在大的环中的边都会同时处于一个其中一个小的环中)。

在tarjan算法中,当lowv>pre[u]时(u是起始点,v是边的下一个点),边(u,v)就是一条桥。而点双连通分量的边的数量可以通过栈的pop次数来统计。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<climits>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<climits>
using namespace std;

const int maxn=10005;
struct Edge
{
	int u,v;
	Edge(int uu,int vv)
	:u(uu),v(vv){}
	Edge(){}
};
int pre[maxn],bccno[maxn],dfs_clock,bcc_cnt;
bool iscut[maxn];
std::vector<int> G[maxn],bcc[maxn];
int ans,ans1;
stack<Edge>s;

int dfs(int u,int fa)
{
	int lowu=pre[u]=++dfs_clock;
	int child=0;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		Edge e=Edge(u,v);
		if(!pre[v])
		{
			s.push(e);
			child++;
			int lowv=dfs(v,u);
			lowu=min(lowu,lowv);
			if(lowv>=pre[u])//条件必须是》=,如果只写==,那么桥的边就不会被弹出栈,造成后面的双连通分量的边数计算错误
			{
				if(lowv>pre[u]) ans1++;//(u,v)是一条桥
				iscut[u]=true;
				bcc_cnt++;bcc[bcc_cnt].clear();
				int cnt=0;
				for(;;)
				{
					cnt++;
					Edge x=s.top();s.pop();
					if(bccno[x.u]!=bcc_cnt)
					{
						bcc[bcc_cnt].push_back(x.u);
						bccno[x.u]=bcc_cnt;
					}
					if(bccno[x.v]!=bcc_cnt)
					{
						bcc[bcc_cnt].push_back(x.v);
						bccno[x.v]=bcc_cnt;
					}
					if(x.u==u&&x.v==v) break;
				}
				if(cnt>bcc[bcc_cnt].size()) ans+=cnt;//当点双连通分量中边的数量大于点的数量
			}
		}
		else if(pre[v]<pre[u]&&v!=fa)
		{
			s.push(e);
			lowu=min(lowu,pre[v]);
		}
	}
	if(fa<0&&child==1) iscut[u]=false;
	return lowu;
}

void find_bcc(int n)
{
	memset(pre,0,sizeof(pre));
	memset(bccno,0,sizeof(bccno));
	memset(iscut,0,sizeof(iscut));
	dfs_clock=bcc_cnt=0;
	for(int i=0;i<n;i++)
	{
		if(!pre[i]) dfs(i,-1);
	}
}

int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0) break;
		int a,b;
		for(int i=0;i<n;i++) G[i].clear();
		for(int i=0;i<m;i++)
		{
			scanf("%d%d",&a,&b);
			G[a].push_back(b);
			G[b].push_back(a);
		}
		ans=0,ans1=0;
		find_bcc(n);
		printf("%d %d\n",ans1,ans);
	}

}
时间: 2024-11-11 03:12:17

HDU 3394 Railway(点双连通分量的应用)的相关文章

Railway HDU - 3394 (点双连通)

Railway HDU - 3394 题意:一个无向图,1求不在任何一个环里的边数:2求在不止一个环里的边数. 第一问明显就是求桥,第二问,如果求出的某个点双连通分量里面边数多于点数,说明不止一个环,那么所有的边都在不止一个环里. 该求点双连通的,,求成了边双连通...要仔细分析问题. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 us

HDU3394.Railway——点双连通分量

http://acm.hdu.edu.cn/showproblem.php?pid=3394 题目描述: 有一个公园有n个景点,公园的管理员准备修建m条道路,并且安排一些形成回路的参观路线.如果一条道路被多条道路公用,那么这条路是冲突的:如果一条道路没在任何一个回路内,那么这条路是不冲突的 问分别有多少条有冲突的路和没有冲突的路 分析: 刚学点双和边双,看见题目分不清哪个是哪个~ 这个题目是求点双的.某条边有冲突,说明该点双连通分量中存在两个以上的环,没有冲突说明这条边是桥 怎么判断一个双连通分

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

HDU - 3394 Railway(连通分量+环)

题目大意:有一个人奇怪的人想要铺路,这个人想把每个环都铺上石头,但是铺石头时不能重复铺,如果重复铺的话,这条边就算损坏 问这个人要损坏多少条边,有多少条边可以不用铺石头 解题思路:不用铺石头的边肯定是桥,因为桥不属于任意一个环 接着判断一下有多少条边会冲突,首先,一个环的话肯定是点-双连通,但点-双连通不一定是个环,所以这个要判断一下. 一个正常的环是要满足 边数=点数 的,如果边数比点数多了,证明这个环被分割成至少三个环了(一个最外围的环,两个被分的小环),可以看出,这三个环每条边都冲突 所以

HDU 3394 Railway (点双联通+圈内判边数)

大意:给定M条边,问有有多少边是不在环上(或环内)的,有多少边是有冲突的(什么是冲突?即在一个环内有多条边将环分割开,即这样的边+上环上边的总数) 思路:求桥的个数比较容易处理,直接(low[v]>dfn[u]即可)主要是怎么找冲突边,我们知道他们一定在一个联通分量内,所以我们将求出的 一组联通分量拿出来,进行遍历看是否所有的连的边在当前的栈中,在的话边数++,因为是无向图,所以最后要除二与联通分量的点相比较即可. 前向星: #include<map> #include<queue

HDU 2242 考研路茫茫——空调教室 (双连通分量+树形DP)

题目地址:HDU 2242 先用双连通分量缩点,然后形成一棵树,然后在树上做树形DP,求出每个点的子树和.然后找最小值即可.需要注意一下重边的问题,第一次返回父节点时可以忽略,因为这是反向边,然后之后再返回的时候就不是反向边了.不能忽略了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #i

HDU 4612——Warm up——————【边双连通分量、树的直径】

Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4612 Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel bet

hdu Caocao&#39;s Bridges(无向图边双连通分量,找出权值最小的桥)

1 /* 2 题意:给出一个无向图,去掉一条权值最小边,使这个无向图不再连同! 3 4 tm太坑了... 5 1,如果这个无向图开始就是一个非连通图,直接输出0 6 2,重边(两个节点存在多条边, 权值不一样) 7 3,如果找到了桥的最小权值为0,也就是桥上的士兵数为0,那么还是要最少派一个 8 士兵过去炸掉桥! 9 10 思路:假设每两个节点最多只有一条边进行相连! 11 进行tarjan算法,如果该算法调用了超过2次,说明这个原图就是不连通的! 12 否则在tarjan算法中将桥存起来!然后

HDU 3749 Financial Crisis 经济危机(并查集,割点,双连通分量)

题意:给一个图n个点m条边(不一定连通),接下来又q个询问,询问两个点是为“不相连”,“仅有一条路径可达”,“有两条及以上的不同路径可达”三种情况中的哪一种.注:两条以上的路径指的是路径上的点连1个点也不重复. 思路:并查集+tarjan求割点. (1)情况一:先并查集处理,如果两个点从一开始就不连通,直接输出zero (2)情况二和情况三:两点既然连通,那么可能是只有1条路径,比如中间隔着一个割点:也可能有多条路径,比如在同一个双连通分量内.那么直接判断其是否在同一个双连通分量内即可,若在同一