[FROM WOJ]#4376 种树

#4376 种树

题面
有一个N个点M条边的无向图,每次选择一个点,并删除该点及其相邻的边,如果变成了一棵树,这这个点就是我们需要的。请找出满足条件的可能的点。
对于 40%的数据: n , m < = 1000 n,m<=1000
另外存在 10%的数据: m = n 1 m=n-1
另外存在 20%的数据: m = n m=n
对于 100%的数据: n , m < = 100000 n,m<=100000

输入
第一行2个正整数N,M,表示N个点M条边,保证N>=2
接下来M行,每行2个整数U,V表示u,v有一条无向边,数据保证无自环与重边

输出
第一行是一个整数ans,表示一共有ans个可能的点
接下来一行输出ans个整数,用空格隔开,按从小到大输出可能的点(数据保证至少存在一个可能的点)

样例输入
6 6
1 2
1 3
2 4
2 5
4 6
5 6

样例输出
3
4 5 6

SOL
暴力怎么打不说了,讲一讲正解。
观察发现,你删去一个点后,剩下 n 1 n-1 个点,得到一棵树,意味着剩下 n 2 n-2 条边,也就是说你删掉一个度数为 m ( n 2 ) m-(n-2) 的点,如果图仍然连通(也就是说你删掉的那个点在原图中不是一个割点),那么就把这个点统计到答案中。
记录每个点的度数,并用 t a r j a n tarjan 求出原图中的割点,这道题就做完了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define N 100005
int n,m;
int ans,output[N];
vector<int>e[N];
inline int rd(){
	int data=0,w=1;static char ch=0;ch=getchar();
	while((!isdigit(ch))&&ch!='-')ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();
	return data*w;
}
int dfn[N],low[N],tcnt,cut[N];
void dfs(int u,int fa){
	int son=0;
	low[u]=dfn[u]=++tcnt;
	for(int register i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(!dfn[v]){
			son++;
			dfs(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])cut[u]=1;		
		}
		else if(dfn[v]<dfn[u]&&v!=fa)low[u]=min(low[u],dfn[v]);
		if(son==1&&u==1)cut[u]=0;
	}
}
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=rd();m=rd();
	for(int register i=1;i<=m;i++){
		int u=rd(),v=rd();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for(int register i=1;i<=n;i++)if(!dfn[i])dfs(i,i);
	for(int register i=1;i<=n;i++){
		if(e[i].size()==m-n+2&&!cut[i])output[++ans]=i;
	}
	printf("%d\n",ans);
	for(int register i=1;i<=ans;i++)printf("%d ",output[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hzq_oi/article/details/87616180
今日推荐