Doves and bombs UVA - 10765 割点

//桥:删掉之后,图就不连通
//边双连通分量:极大的不含有桥的连通块
//不管删掉哪条边,都是连通的
//任意两个点之间,至少存在两条不相交的路径

//割点:如果把某个点和它所关联的所有边都删掉,图就不连通
//每一个割点至少属于两个双连通分量
//点双连通分量:极大的不包含割点的连通块

//两个割点之间的边,不一定是桥
//一个桥的两个端点,不一定是桥
//边双连通分量不一定是点双连通分量
//点双连通分量不一定是边双连通分量

//找桥:x->y是桥 等价于 dfs(x)<low(y)
//找遍双连通分量:做法1:将所有桥删掉,
//				  做法2:用一个栈,搜索完dfs(x)==low(x),那么当前还在栈中的其他点,就是双连通分量的其他点

//x--y
//如何判断是不是割点:当low(y)>=dfn(x),
//						1.如果x不是根节点,那么x就是割点 ,
//						2.如果x是根节点,那么至少存在两个y,low(y)>=dfn(x)
//如何求点的双连通分量:
//



//统计所有连通块个数cnt
//依此枚举从哪个块中删,删哪个点,可以把当前块儿分成s部分
//那么答案就是s+cnt-1的最大值
//那么就是找s
//用类似求割点的方法来做:
//如果dfn(x)<=low(y),那么如果把x删掉,y就会单独出来,那么就会多一个单独的子树,多一个块儿
//特判:如果x不是根节点,删掉之后就会有三部分(一般情况);如果是,删掉之后就会有两部分
//也就是枚举删除哪个割点
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10050;
int n, m;
int h[N], e[N<<3], ne[N<<3], idx;
int dfn[N], low[N], timestamp;
//根节点,每个点删掉之后最多可以分为几块
int root;
inline int read()
{
	int x_=0,f_=1;
	char c_=getchar();
	while(c_<'0'||c_>'9')
	{
		if(c_=='-') f_=-1;
		c_=getchar();
	}
	while(c_>='0'&&c_<='9')
	{
		x_=(x_<<1)+(x_<<3)+c_-'0';
		c_=getchar();
	}
	return x_*f_;
}
struct node
{
	int id,w;
} ans[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void tarjan(int u)
{
	dfn[u] = low[u] = ++ timestamp;
	//当前块儿内已经可以分出来的子树的个数
	int cnt = 0;
	for (int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		if (!dfn[j])
		{
			tarjan(j);
			low[u] = min(low[u], low[j]);
			//说明j走不到u上面
			if (low[j] >= dfn[u])
			{
				cnt ++;
				if(u!=root || cnt>1)
					++ans[u].w;
			}
		}
		//如果已经搜过了
		else
			low[u] = min(low[u], dfn[j]);
	}
	//如果u不是根节点,而且cnt大于0
	//还要加上父节点的那一部分
	if (u != root && cnt)
		cnt ++ ;
	//取大
}
inline bool cmp_(node aa,node bb)
{
	if(aa.w==bb.w) return aa.id < bb.id;
	return aa.w > bb.w;
}
int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		if(!n && !m)
			return 0;
		//初始化,有判重数组的作用
		memset(dfn, 0, sizeof dfn);
		memset(h, -1, sizeof h);
		for(int i=1; i<=n; i++) ans[i]= {i,0};
		idx = timestamp = 0;
		while (1)
		{
			int a=read(), b=read();
			if(a==-1 && b==-1)
				break;
			a++,b++;
			add(a, b), add(b, a);
		}
		for(int i=1; i<=n; i++)
			ans[i].id=i;
		root=1;
		tarjan(1);
		sort(ans+1,ans+1+n,cmp_);
		for(int i=1; i<=m; ++i)
			printf("%d %d\n",ans[i].id-1,ans[i].w+1);
		printf("\n");
	}
	return 0;
}


posted @ 2020-05-08 23:20  晴屿  阅读(109)  评论(0编辑  收藏  举报