题目の大意:
现在有一个无向图,我们可以删去一个节点和与其相连的边,使得修改后的图变成一棵树,求所有可能的方案和方案数~
比赛时の想法:
暴力枚举每一个删除的点,然后暴力判断一下删去这个点和他相连的边后图是否变成一颗树,m=n-1时删去一个度数为1的边。
正解:
一开始有n个点,在删去一个点后成为一颗树,那么树中就有n-2条边,当前删去的点如果是合法的,那么它的度数就是m-(n-2)但是考虑到删去一个点后可能把图成两个部分,所以当这个点时无向图的割点时这个点也是不合法的,那么我们直接tarjan求割点就好了
贴代码~
var
dfn,low,fa:array[0..100005]of longint;
a:array[0..100005,0..105]of longint;
bz,b:array[0..100005]of boolean;
i,j,k,l,n,m,x,y,p,ans:longint;
function min(x,y:longint):longint;
begin
if x>y then exit(y) else exit(x);
end;
procedure dfs(x:longint);
var
i,j,son:longint;
begin
b[x]:=true;
inc(p);
dfn[x]:=p;
low[x]:=p;
son:=0;
for i:=1 to a[x,0] do
begin
if b[a[x,i]]=false then
begin
inc(son);
fa[a[x,i]]:=x;
dfs(a[x,i]);
low[x]:=min(low[a[x,i]],low[x]);
if (dfn[x]=1) and (son>=2) then bz[x]:=true else
if (dfn[x]>1) and (low[a[x,i]]>=dfn[x]) then bz[x]:=true;
end else
if fa[x]<>a[x,i] then low[x]:=min(low[x],dfn[a[x,i]]);
end;
end;
begin
// assign(input,'2.in'); reset(input);
readln(n,m);
for i:=1 to m do
begin
readln(x,y);
inc(a[x,0]);
a[x,a[x,0]]:=y;
inc(a[y,0]);
a[y,a[y,0]]:=x;
end;
dfs(1);
x:=m-n+2;
ans:=0;
for i:=1 to n do
if (a[i,0]=x) and (bz[i]=false) then inc(ans);
writeln(ans);
for i:=1 to n do
if (a[i,0]=x) and (bz[i]=false) then write(i,' ');
writeln;
// close(input);
end.