poj 3648 Wedding 2-SAT输出

来源:互联网 发布:克里斯埃文斯知乎 编辑:程序博客网 时间:2024/05/16 15:57

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


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

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

输出方法是,对原图求一次强连通分量,然后看每组中的两个点是否属于同一个强连通分量,如果存在这种情况,那么无解

然后对于缩点后的图G',我们将G'中所有边转置。进行拓扑排序。

对于缩点后的所有点,我们先预处理求出所有冲突顶点。例如缩点后Ai所在强连通分支的ID

id[ Ai],同理~Ai id[ ~Ai ],所以冲突顶点

conflict[ id[Ai]]=conflict[ id[~Ai] ];

同理conflict[ id[~Ai]]=conflict[ id[Ai] ];

设缩点后有Nscc个点。

然后对拓扑序进行染色,初始化所有点color均为未着色

顺序遍历得到的拓扑序列,对于未着色的点x,将x染成红色,同时将所有与x矛盾的点conflic[x]染成蓝色。

2-sat的一组解就等价于所有缩点后点颜色为红色的点,也就是color[ id[i] ]=RED的所有点


唉调了半个早上最后才发现原来是要输出跟新娘坐同侧的~~

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


代码:

var  n,m,e,d,sum,tot:longint;  last,belong,color,dfn,low,con,du,stack,state:array[1..400] of longint;  f:array[1..400] of boolean;  side:array[1..200000] of record    x,y,next:longint;  end;function next(x:longint):longint;begin  if x>n then exit(x-n)         else exit(x+n);end;procedure add(x,y:longint);begin  inc(e);  side[e].x:=x;  side[e].y:=y;  side[e].next:=last[x];  last[x]:=e;end;function min(x,y:longint):longint;begin  if x<y then exit(x)         else exit(y);end;procedure init;var  c:char;  s:string;  x,y,i:longint;begin  fillchar(last,sizeof(last),0);  e:=0;  for i:=1 to m do  begin    read(c);    s:='';    while c in ['0'..'9'] do    begin      s:=s+c;      read(c);    end;    val(s,x);    inc(x);    if c='w' then x:=x+n;    read(c);    read(c);    s:='';    while c in ['0'..'9'] do    begin      s:=s+c;      read(c);    end;    val(s,y);    inc(y);    if c='w' then y:=y+n;    readln;    add(x,next(y));    add(y,next(x));  end;  add(1+n,1);end;procedure dfs(x:longint);var  i:longint;begin  inc(d);  dfn[x]:=d;  low[x]:=d;  inc(tot);  stack[tot]:=x;  f[x]:=true;  i:=last[x];  while i>0 do    with side[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 dfn[x]=low[x] then  begin    inc(sum);    repeat      i:=stack[tot];      dec(tot);      f[i]:=false;      belong[i]:=sum;    until i=x;  end;end;procedure tarjan;var  i:longint;begin  fillchar(dfn,sizeof(dfn),0);  fillchar(low,sizeof(low),0);  fillchar(f,sizeof(f),false);  sum:=0;  tot:=0;  d:=0;  for i:=1 to n*2 do    if dfn[i]=0 then dfs(i);end;procedure topsort;var  head,tail,i:longint;begin  head:=0;  tail:=0;  for i:=1 to sum do    if du[i]=0 then    begin      inc(tail);      state[tail]:=i;    end;  repeat    inc(head);    i:=last[state[head]];    while i>0 do      with side[i] do      begin        dec(du[y]);        if du[y]=0 then        begin          inc(tail);          state[tail]:=y;        end;        i:=next;      end;  until head>=tail;end;procedure dfs_blue(x:longint);var  i:longint;begin  color[x]:=-1;  i:=last[x];  while i>0 do    with side[i] do    begin      if color[y]=0 then dfs_blue(y);      i:=next;    end;end;procedure dfs_red;var  i:longint;begin  for i:=1 to sum do    if color[state[i]]=0 then    begin      color[state[i]]:=1;      dfs_blue(con[state[i]]);    end;end;procedure print;var  u,i:longint;begin  for i:=2 to n do  begin    if i>2 then write(' ');    if color[belong[i]]=-1      then write(i-1,'h')      else write(i-1,'w');  end;  writeln;end;procedure work;var  i:longint;begin  for i:=1 to n do  begin    if belong[i]=belong[i+n] then    begin      writeln('bad luck');      exit;    end;    con[belong[i]]:=belong[i+n];    con[belong[i+n]]:=belong[i];  end;  fillchar(last,sizeof(last),0);  fillchar(du,sizeof(du),0);  for i:=1 to e do    with side[i] do      if belong[x]<>belong[y] then      begin        add(belong[y],belong[x]);        inc(du[belong[x]]);      end;  topsort;  fillchar(color,sizeof(color),0);  dfs_red;  print;end;begin  readln(n,m);  while n+m>0 do  begin    init;    tarjan;    work;    readln(n,m);  end;end.


0 0
原创粉丝点击