1. 题目
POJ 3207
2. 题目实质
平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。问能不能连接这m条边,使这些边都不相交。(比如两条边分别是1-2,2-3,则可以连接。若有三条边分别时1-5,2-6,3-7则一定会出现相交)。
3. 算法
2-SAT。(NOI)
题意可能刚开始不是很好理解,比如1 5连边,2,6连边,由于点是顺序排列的,一画图就可以发现,这两条边必须一个从圆外面连,一个从内部连,否则就会相交。如果再加入3 7这条边,那么就必须相交了。
这样,就可以转化成标准的2-sta问题:
1:每个边看成2个点:分别表示在内部连接和在外部连接,只能选择一个。计作点i和点i'
2:如果两条边i和j必须一个画在内部,一个画在外部(一个简单判断就可以)
那么连边:
i->j’, 表示i画内部的话,j只能画外部,即j’
j->i’,同理
i’->j,同理
j’->i,同理
然后就是2-sat算法了,tarjan一下,如果有i和i'同属于一个强联通,返回false,否则就成立。
4. 注意事项
对于 NOIP 的孩子们来说, tarjan 素超纲滴。
5. 代码
2-sat (ZSZ)
program fot;
var belong,l,r:array[0..500010] of longint;
instack:array[0..500010] of boolean;
low,dfn,stack,f:array[0..500010] of longint;
e:Array[0..500010] of record
y,n:longint;
end;
o,i,n,top,j,m,time,number,q,z:longint;
boo:boolean;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
procedure swap(var a,b:longint);
var c:longint;
begin
c:=a;a:=b;b:=c;
end;
procedure add(a,b:longint);
begin
inc(o);
e[o].y:=b;
e[o].n:=f[a];
f[a]:=o;
end;
procedure tarjan(x:longint);
var t:longint;
begin
inc(time);
dfn[x]:=time;
low[x]:=time;
inc(top);
instack[x]:=true;
stack[top]:=x;
t:=f[x];
while t<>0 do
begin
if (dfn[e[t].y]=0) then
begin
tarjan(e[t].y);
low[x]:=min(low[x],low[e[t].y]);
end
else
if instack[e[t].y]=true then
low[x]:=min(low[x],dfn[e[t].y]);
t:=e[t].n;
end;
if dfn[x]=low[x] then
begin
inc(number);
repeat
t:=stack[top];
dec(top);
instack[t]:=false;
belong[t]:=number;
until t=x;
end;
end;
begin
readln(n,m);
for i:= 1 to m do
begin
readln(l[i],r[i]);
if (r[i]<l[i]) then swap(r[i],l[i]);
end;
o:=0;
fillchar(e,sizeof(e),0);
fillchar(f,sizeof(f),0);
fillchar(dfn,sizeof(dfn),0);
fillchar(stack,sizeof(stack),0);
fillchar(low,sizeof(low),0);
fillchar(belong,sizeof(belong),0);
fillchar(instack,sizeof(instack),false);
for i:= 1 to m do
for j:= i+1 to m do
begin
if ((l[i]>l[j])and(l[i]<r[j])and(r[i]>r[j]))or
((l[j]>l[i])and(l[j]<r[i])and(r[j]>r[i])) then
begin
add(i,j+m);
add(j+m,i);
add(j,i+m);
add(i+m,j);
end;
end;
top:=0;
for i:= 1 to 2*m do
if dfn[i]=0 then tarjan(i);
boo:=true;
for i:= 1 to m do
if belong[i]=belong[i+m] then
begin
boo:=false;
break;
end;
if boo=true then writeln('panda is telling the truth...')
else writeln('the evil panda is lying again');
end.