题意:给出n对筷子,每对筷子两端都有颜色,不同筷子相同颜色的一端可以连在一起。问是否能让所有筷子连成一条线段。
分析:一开始我的想法是把每种颜色的数量统计起来,若数量为单数的颜色>=3或=1则Impossible,反之则Possible。但后来我发现我错了,反例:red,green;blue,blue。
然后看了别人的题解才发现是要先构图再用欧拉路(一笔画问题)来判断。
构图的方法为每种颜色为一个点,一对筷子为一条边。
我们知道无向图中的欧拉回路必须要满足两个充要条件:一是度为奇数的点有两个或没有;二是图是连通的。
第一个好搞,直接统计一下就好了,若度为奇数的点>=3或=1则Impossible,不然就要去判断图的连通性。
判断图的连通性比较好的方法是并查集,也就是一开始每一个顶点都是一个连通块,每加入一条边则把这条边两端对应的连通块合并,最后判断一下是否所有点都在统一集合内就好了。
代码:
const maxn=500000; var a1,i,tot,m,n:longint; s:string; x:char; w:array[1..maxn] of char; a:array[1..maxn,1..3] of longint; son:array[1..maxn,1..26] of longint; f:array[1..maxn] of longint; p,q:array[1..maxn] of longint; function insert(d:longint;s:string):longint; var i:longint; begin if s='' then begin if a[d,3]=0 then begin inc(n); a[d,3]:=n; end; inc(a[d,2]); if a[d,2] mod 2=1 then inc(tot) else dec(tot); exit(a[d,3]); end; for i:=1 to a[d,1] do if w[son[d,i]]=s[1] then begin delete(s,1,1); insert:=insert(son[d,i],s); exit; end; inc(a[d,1]); inc(a1); son[d,a[d,1]]:=a1; w[a1]:=s[1]; delete(s,1,1); insert:=insert(a1,s); end; function find(x:longint):longint; begin if f[x]=x then exit(x); find:=find(f[x]); f[x]:=find; end; begin a1:=1; while not eof do begin inc(m); read(x); s:=''; while x<>' ' do begin s:=s+x; read(x); end; p[m]:=insert(1,s); readln(s); q[m]:=insert(1,s); end; if (tot>2)or(tot=1) then begin writeln('Impossible'); exit; end; for i:=1 to n do f[i]:=i; for i:=1 to m do if find(p[i])<>find(q[i]) then f[find(p[i])]:=find(q[i]); tot:=find(1); for i:=2 to n do if find(i)<>tot then begin writeln('Impossible'); exit; end; writeln('Possible'); end.