【hdoj3394】railway

【hdoj3394】railway

题目描述(花里胡哨)

有一个公园有n个景点,这n个景点由m条无向道路连接而成。

公园的管理员准备规划一一些形成回路的参观路线(参观路线不能经过同一个景点,是一个简单环)。如果一条道路被多条参观路线公用,那么这条路是冲突的;如果一条道路没在任何一个回路内,那么这条路是多余的道路。

问分别有多少条有冲突的路和多余的路

输入格式

包括多组数据 每组数据第一行2个整数n,m

接下来m行,每行2个整数x,y,表示从x到y有一条无向边。

输入数据以n=0,m=0结尾

输出格式

一行2个整数,表示你要求的多余的道路和冲突的道路的数量。

样例数据

input

8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0

output

1 5

数据规模与约定

hdoj 3394

0 < n <= 10000, 0 <= m <= 100000

时间限制:1s1s

空间限制:256MB

这题就是:给出一个无向图,求出割边的条数,并求出存在在多个环中的边的条数。

第一问求割边。
第二问求有两个简单环以上的点双的边数之和。(证明在后面)

样例解释:

这个是图,可以知道0,1,2,3形成一个简单环,4,5,7形成简单环,5,6,7形成简单环,5,6,7,4形成简单环,那么3到4之间的路就是多余的道路,也就是割边(易证)。冲突的路就是画了圈的

5个。

其实就是有两个简单环以上的点双的边数之和。

可以看一个简单的例子。

这就是一条路线,但是如果中间加一条线就不一样了。

这就是一个用两条旅游路线及以上的点双(点的数量小于边的数量)。1,4,2      1,4,3     1,2,4,3   三条路线,所以所有的路都是重复的。

所以重复的路就是有两个简单环以上的点双的边数之和了。

然后是**代码。

#include<bits/stdc++.h>
using namespace std;
struct EE
{
	int x,y;
}e[200001];
long long  ans1,ans2;
int m;
int E;
int tot=1,n,x,y,num;
int u,v,w;
int top;
int dfn[100001],low[100001],d[100001],head[100001];
int color[100001],X[100001],c[100001]; 
int Low[100001],s[100001],a[100001]; 
inline void add(int a,int b)
{
	e[++tot].x=head[a];
	head[a]=tot;
	e[tot].y=b;
}
inline void tarjan(int x,int fa)
{
	dfn[x]=low[x]=Low[x]=++num;
	s[++top]=x;
	for(int i=head[x];i;i=e[i].x)
	{
		int y=e[i].y;
		if(dfn[y]==0)
		{
			tarjan(y,i);
			Low[x]=min(Low[x],Low[y]);
			low[x]=min(low[x],low[y]);
			if(dfn[x]<Low[y]) ans1++;//累加边双
			if(dfn[x]<=low[y])
			{
				memset(d,0,sizeof(d));
				v=0;
				u=0;
				while(u!=y)
				{
					u=s[top--];
					a[++v]=u;
					d[u]=1;
				}
				a[++v]=x;
				d[x]=1;
				w=0;//v就是有两个简单环及以上的点双的点数 ,w是边数 
				for(int i=1;i<=v;i++)
				{
					for(int j=head[a[i]];j;j=e[j].x)
					{
						if(d[e[j].y]) w++;
					}
				}
				if(w/2>v) ans2+=w/2; //判断点的数量小于边的数量,然后累加。 
			}
		}
		else
		{
			low[x]=min(low[x],dfn[y]);
			if(i!=(fa^1))Low[x]=min(Low[x],dfn[y]);
		}
	}
}
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int main()
{
//	freopen("way.in","r",stdin);
//	freopen("way.out","w",stdout);
	for(;;)
	{
		n=read();
		m=read();
		if(!n&&!m) break;
		memset(head,0,sizeof(head));
		tot=1;
		num=0;
		top=0;
		ans1=0;
		ans2=0;
		for(int i=1;i<=m;i++)
		{
			x=read();
			y=read();
			x++;
			y++;
			if(x!=y)
			{
				add(x,y);
				add(y,x);
			}
		}
		memset(dfn,0,sizeof(dfn));
		for(int i=1;i<=n;i++)
		{
			if(!dfn[i]) tarjan(i,-1);
		}
		printf("%d %d\n",ans1,ans2);
	}
	return 0;
}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值