SGU101 无向图欧拉路径

题意简述
每个多米诺骨牌的面都被一条线分成两个方形,两边各有一定点数。 N(N100) 个多米诺骨牌,每个骨牌左右两侧分别有一个 06 的整数(骨牌可以旋转以调换其左右两数),求一种把这些骨牌从左到右排列的方案,使得所有相邻的两数字相等(即左边骨牌右侧的数字等于右边骨牌左侧的数字)。


分 析
显然可以在骨牌间连边,但这样就会变成求哈密顿路问题,NPC问题,显然无法解决。
转换思路,在每个骨牌的两个数字间连一条无向边,直接求欧拉路径即可。


代码实现
在DFS中直接打印路径,由于欧拉图可以被分解为若干个边不相交的环,所以无论是何种搜的顺序,都是成立的。

type
  edge=record
  re,next,num:longint;
end;
var
i,n,x,y,s,cnt,tot:longint;
f,du:array[0..10] of longint;
e:array[0..220] of edge;
boo,vs:array[0..220] of boolean;

procedure add(x,y,tmp:longint);
begin
  inc(cnt);
  with e[cnt] do
  begin
    re:=y;next:=f[x];num:=tmp;
  end;
  f[x]:=cnt;
end;

procedure check(x:longint);
var
tmp:longint;
begin
  tmp:=f[x];
  while tmp<>0 do
  begin
    with e[tmp] do
    if not vs[tmp] then 
    begin vs[tmp]:=true;inc(tot);check(re);end;
    tmp:=e[tmp].next;
  end;
end;

procedure dfs(x:longint);
var
tmp:longint;
begin
  tmp:=f[x];
  while tmp<>0 do
  begin
    if not boo[tmp] then
    begin
      boo[tmp]:=true;boo[tmp xor 1]:=true;
      dfs(e[tmp].re);
      write(e[tmp].num,' ');
      if odd(tmp) then writeln('+') else writeln('-');
    end;
    tmp:=e[tmp].next;
  end;
end;

begin
  readln(n);cnt:=1;
  for i:=1 to n do
  begin
    readln(x,y);
    add(x,y,i);add(y,x,i);
    inc(du[x]);inc(du[y]);
  end;
  for i:=0 to 6 do
  if du[i] and 1=1 then begin inc(tot);s:=i;end;
  if (tot<>2)and(tot<>0) then
  begin
    writeln('No solution');
    halt;
  end;
  tot:=0;
  for i:=0 to 6 do
  if f[i]<>0 then
  begin
    check(i);break;
  end;
  if tot<>2*n then
  begin
    writeln('No solution');
    halt;
  end;
  while f[s]=0 do inc(s);
  dfs(s);
end.

DFS在图中点比较多的时候容易爆栈(当然这题不会),所以也练习了手工栈的实现方法。

type
  edge=record
  re,next,num:longint;
end;
var
i,n,x,y,s,cnt,tot:longint;
f,du:array[0..10] of longint;
e:array[0..220] of edge;
boo,vs:array[0..220] of boolean;
stack,ans:array[0..220] of longint;

procedure add(x,y,tmp:longint);
begin
  inc(cnt);
  with e[cnt] do
  begin
    re:=y;next:=f[x];num:=tmp;
  end;
  f[x]:=cnt;
end;

procedure check(x:longint);
var
tmp:longint;
begin
  tmp:=f[x];
  while tmp<>0 do
  begin
    with e[tmp] do
    if not vs[tmp] then 
    begin vs[tmp]:=true;inc(tot);check(re);end;
    tmp:=e[tmp].next;
  end;
end;

procedure dfs(x:longint);
var
tmp,top:longint;
flag:boolean;
begin
  top:=1;stack[1]:=x;
  while top<>0 do
  begin
    tmp:=f[stack[top]];flag:=false;
    while tmp<>0 do
    begin
      if not boo[tmp] then
      begin
        boo[tmp]:=true;boo[tmp xor 1]:=true;
        inc(top);stack[top]:=e[tmp].re;
        ans[top]:=tmp;flag:=true;break;
      end;
      tmp:=e[tmp].next;
    end;
    if not flag then
    begin
        if top=1 then exit;
      write(e[ans[top]].num,' ');
      if odd(ans[top]) then writeln('+') else writeln('-');
      dec(top);
    end;
  end;
end;

begin
  readln(n);cnt:=1;
  for i:=1 to n do
  begin
    readln(x,y);
    add(x,y,i);add(y,x,i);
    inc(du[x]);inc(du[y]);
  end;
  for i:=0 to 6 do
  if du[i] and 1=1 then begin inc(tot);s:=i;end;
  if (tot<>2)and(tot<>0) then
  begin
    writeln('No solution');
    halt;
  end;
  tot:=0;
  for i:=0 to 6 do
  if f[i]<>0 then
  begin
    check(i);break;
  end;
  if tot<>2*n then
  begin
    writeln('No solution');
    halt;
  end;
  while f[s]=0 do inc(s);
  dfs(s);
end.

你可能感兴趣的:(解题报告)