poj 2513 Colored Sticks 字典树+并查集+欧拉路

题意:给出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.


你可能感兴趣的:(poj 2513 Colored Sticks 字典树+并查集+欧拉路)