poj 3648 Wedding 2_SAT
2016-06-14 17:04
295 查看
题目大意
有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.
有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.
相关文章推荐
- 浅谈python新手中常见的疑惑及解答
- 视频下载工具 :you-get
- This text field does not specify an inputType or a hint
- 自定义surfaceview
- enumerate
- Juicer 中文文档
- 体外诊断(POCT)之检测卡配置文件
- Android自定义LinearLayout实现左右侧滑菜单,完美兼容ListView、ScrollView、ViewPager等滑动控件
- A001-书籍-像程序员一思考
- Class.forName()用法详解
- 实习杂记(23):ant里面condition属性测试
- js倒计时及时间差
- REST与SOA两种架构的异同比较
- Eclipse一闪而过解决最彻底的办法
- 七牛生成token链接
- javascript之函数参数
- jquery加载页面的方法(页面加载完成就执行)
- Bulb Switcher
- Android Studio 第一次配置及其使用
- 浅谈JS的数组遍历方法