poj 3648 Wedding 2_SAT

题目大意

  有n对夫妇第i对夫妇表示为i-1h、i-1w。每对夫妇必须坐在桌子的不同侧。现在有m对通奸关系,新娘(0号妻子)不想看到她对面的任意两个人有通奸关系。求一种满足的坐法并输出坐新娘同侧的人。

 

分析

  因为每对夫妻要么夫左妻右要么夫右妻左,所以很明显是一道2-SAT问题。

  建图:设i'为第i个人的伴侣。对于某对通奸关系i和j,则连边i->j',j->i'。最后从新娘连一条边指向新郎以至于必须选新郎。

  话说输出方案真的好麻烦,期望以后在比赛中不要遇到这样的题。

  其实麻烦的地方是建图,所有的2—SAT都这样。

  有多组数据,记得要重置数组。

 

代码

type
  arr=record
    x,y,next:longint;
end;

var
  a,a1:array[1..200000] of arr;
  f:array[1..400] of boolean;
  ls,zan,g,con,b,c,co:array[1..400] of longint;
  dfn,low:array[1..400] of longint;
  x,y,z:array[1..400] of longint;
  tot,sum,n,m:longint;
  i,j,k:longint;
  e,d:longint;
  cc:char;
  s:string;

procedure add(x,y:longint);
begin
  inc(e);
  a[e].x:=x;
  a[e].y:=y;
  a[e].next:=ls[x];
  ls[x]:=e;
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

procedure dfs(x:longint);
var
  i:longint;
begin
  inc(d);
  dfn[x]:=d;
  low[x]:=d;
  inc(tot);
  zan[tot]:=x;
  f[x]:=true;
  i:=ls[x];
  while i>0 do
    with a[i] do
    begin
      if dfn[y]=0
        then begin
               dfs(y);
               low[x]:=min(low[x],low[y]);
             end
        else if f[y] then low[x]:=min(low[x],dfn[y]);
      i:=next;
    end;
  if low[x]=dfn[x] then
  begin
    inc(sum);
    repeat
      i:=zan[tot];
      dec(tot);
      f[i]:=false;
      g[i]:=sum;
    until i=x;
  end;
end;

procedure tarjan;
var
  i:longint;
begin
  fillchar(f,sizeof(f),0);
  fillchar(low,sizeof(low),0);
  fillchar(dfn,sizeof(dfn),0);
  fillchar(g,sizeof(g),0);
  tot:=0;
  sum:=0;
  d:=0;
  for i:=1 to n*2 do
    if dfn[i]=0
      then
        dfs(i);
end;

procedure topsort;
var
  i,j,k:longint;
  head,tail:longint;
begin
  head:=0;
  tail:=0;
  fillchar(b,sizeof(b),0);
  for i:=1 to sum do
    if c[i]=0 then
      begin
        tail:=tail+1;
        b[tail]:=i;
      end;
  if tail=0 then exit;
  repeat
    head:=head+1;
    i:=ls[b[head]];
    while i<>0 do
      with a[i] do
        begin
          c[y]:=c[y]-1;
          if c[y]=0
            then
              begin
                tail:=tail+1;
                b[tail]:=y;
              end;
          i:=next;
        end;
  until tail=head;
end;

procedure set_b(r:longint);
var
  i,j,k:longint;
begin
  i:=ls[r];
  co[r]:=-1;
  while i>0 do
    with a[i] do
      begin
        if co[y]=0
          then set_b(y);
        i:=next;
      end;
end;

procedure set_r;
var
  i,j,k:longint;
begin
  for i:=1 to sum do
    if co[b[i]]=0
      then
        begin
          co[b[i]]:=1;
          set_b(con[b[i]]);
        end;
end;

procedure print;
var
  i,t1,t2:longint;
begin
  for i:=2 to n do
  begin
    if i>2 then write(' ');
    if co[g[i]]=-1
      then
        write(i-1,'h')
      else
        write(i-1,'w');
  end;
  writeln;
end;

procedure work;
var
  i,j,k:longint;
begin
  fillchar(con,sizeof(con),0);
  for i:=1 to n do
    begin
      if g[i]=g[i+n] then
        begin
          writeln('bad luck');
          exit;
        end;
      con[g[i]]:=g[i+n];
      con[g[i+n]]:=g[i];
    end;
  fillchar(ls,sizeof(ls),0);
  fillchar(c,sizeof(c),0);
  for i:=1 to e do
    with a[i] do
      if g[x]<>g[y] then
        begin
          add(g[y],g[x]);
          c[g[x]]:=c[g[x]]+1;
        end;
  topsort;
  fillchar(co,sizeof(co),0);
  set_r;
  print;
end;

function ban(x:longint):longint;
begin
  if x>n then exit(x-n);
  exit(x+n);
end;

procedure init;
var
  i,j,k:longint;
begin
  fillchar(ls,sizeof(ls),0);
  for i:=1 to m do
    begin
      read(cc);
      s:='';
      while cc in ['0'..'9'] do
        begin
          s:=s+cc;
          read(cc);
        end;
      val(s,j);
      j:=j+1;
      if cc='w' then j:=j+n;
      read(cc);
      read(cc);
      s:='';
      while cc in ['0'..'9'] do
        begin
          s:=s+cc;
          read(cc);
        end;
      val(s,k);
      k:=k+1;
      if cc='w' then k:=k+n;
      add(j,ban(k));
      add(k,ban(j));
      readln;
    end;
  add(1+n,1);
end;

begin
  readln(n,m);
  while n+m>0 do begin
  e:=0;
  init;
  tarjan;
  work;
  readln(n,m);
  end;
end.


posted @ 2016-06-14 17:04  一个响亮的蒟蒻  阅读(133)  评论(0编辑  收藏  举报