[NOIP simulation test]: Home (spire)

Topic Portal (internal question 7)


Input Format

A first line integer T, T represents the total data set.
For each test, the first line of the two numbers n, m denotes n-buildings, m roads.
Next m lines of two integers u, v, represents the buildings connected between the u and v-th building.


Output Format

For each test, a total of two output lines.
The first line represents a total number x of x must pass through the points (1 point and not including n dots).
The next line number x, x, this must pass through two points are those points. Ascending to the output.
Note: If the first line of output 0, then the output of the second row next thing you should only have one line break.


Sample

Sample input 1:

1
4 3
1 2
2 3
3 4

Sample output 1:

2
2 3

Sample input 2:

1
5 5
1 2
2 3
3 4
4 5
4 1

Sample Output 2:

1
4


Data range and tips

$T\leqslant 10$。

$n\leqslant 200,000$。

There may be multiple edges or loopback. $ M \ leqslant n $.


answer

Are to this question, first of all, we should expect a cut point, spire-point reduction is essential.

However, a necessary point must be cut point, but not necessarily point cut is a necessary point, because the only point on the round side trees 1 to n of this chain is a necessary point.

So how should we do it?

Clearly point can shrink spire, built map, running on the new map, find back, but realized too complex, larger constant.

Therefore, we consider another approach.

In spire algorithm, if a timestamp is less backtracking point value of its child nodes, then it must be a cutpoint.

So, if a son point timestamp is less than the time stamp is equal to n, then it must pass through the point on the path 1 to n.

你可能会仍给我类似下面这张图:

 

如果我们先访问了点2,那么点3和点4的时间戳都比点5小,怎么办呢?

访问了点2,如果我们先访问了点3,那么点4还没有被访问过,而点4恰恰是判定点2为割点的条件,而此时点2连割点的条件都没有满足,更不用考虑是不是必经点了。

如果我们先访问了点4,那么点5还没有被访问到,所以也不成立。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec
{
	int nxt;
	int to;
}e[1000000];
int head[200001],cnt;
int n,m;
int dfn[200001],low[200001],tot;
bool cut[200001];
int ans;
void pre_work()
{
	cnt=tot=ans=0;
	for(int i=1;i<=n;i++)
		head[i]=dfn[i]=low[i]=cut[i]=0;
}
void add(int x,int y)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
void tarjan(int x)
{
	dfn[x]=low[x]=++tot;
	int flag=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		if(!dfn[e[i].to])
		{
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
			if(dfn[x]<=low[e[i].to]&&dfn[e[i].to]<=dfn[n])//加一个判定条件
			{
				flag++;
				if(x!=1||flag>1){ans++;cut[x]=1;}
			}
		}
		else low[x]=min(low[x],dfn[e[i].to]);
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		pre_work();
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			add(u,v);
			add(v,u);
		}
		tarjan(1);
		printf("%d\n",ans);
		for(int i=1;i<=n;i++)
			if(cut[i])printf("%d ",i);
		puts("");
	}
	return 0;
}

不管你怎么说,反正我觉得这个代码比其他人的代码简洁多了~


rp++

Guess you like

Origin www.cnblogs.com/wzc521/p/11248404.html