题目大意:
国王手下有M个大臣,他们有一天对国王要处理的N件事务进行投票。每个大臣可以对两件事务赞成或反对,格式如下:x c_x y c_y表示这个大臣对事务x的态度为c_x,对事务y的态度为c_y。如果国王的决定和某个大臣的两个意见都不同,那么这个大臣就会离开国王。小C认为不能让任何一个大臣离开国王,否则国王就无法正常地处理自己的事务。请你帮助小C做个决定。
如果小C无论如何都只能让至少一个大臣离开国王,则输出“IMPOSSIBLE”(不含双引号),否则输出一个长度为N的字符串,如果第i件事务必须赞成,则第i个字符为“Y”;如果第i件事务必须反对,则第i个字符为“N”,否则第i个字符为“?”。
x, y为整数,c_x, c_y为“Y”(表示赞成)或“N”(表示反对)
对于50%的数据,1<=N<=10,1<=M<=40;
对于全部的数据,1<=N<=1000,1<=M<=4000。
题解:
这题一开始并没有什么想法,各种暴力都套不进。。。
后来看了几篇博客,才知道其实很简单
对于一对[x,cx,y,cy]而言,你要使得大臣不离开至少要有一个满足
则,
举例一种情况:
1 Y 2 Y
这时候,你要留下大臣,就要满足1 Y 或者 2 Y
我们可以这样理解
对1是N时对2必定要是Y
对2是N时对1必定要是Y
这时候其他的同理
我们就可以将这些关系建成一条条边
然后枚举每一个事务的Y/N 两种状态,沿着边跑,
判断是否当你对i持Y意见时,你是否必定必须要对i持N意见!
就是你i选了Y以后那些边对应的意见就要相对应的做出选择,看这些选择时候能使得事务i必定出现N
你对i持N意见时,同理
但2个意见都没冲突时,输出?
Y没N有,输出Y
N没Y有,输出N
都有冲突,哇!IMPOSSIBLE
这或许就是传说中的2-SAT
代码:
const
maxn=4001;
var
a:array[0..maxn,1..2] of longint;
go,next:array [0..2*maxn] of longint;
cp,list:array [0..2001] of longint;
n,m,i,j,rp,p,q:longint;
check,rp1,rp2:boolean;
ans:ansistring;
x1,x2:char;
procedure add(x,y:longint);
begin
inc(p);
go[p]:=y;
next[p]:=list[x];
list[x]:=p;
end;
procedure work(x:longint);
var
i:longint;
begin
if not(rp1) then exit;
if x=rp then
begin
rp1:=false;
exit;
end;
cp[x]:=q;
i:=list[x];
while i>0 do
begin
if cp[go[i]]<>q then work(go[i]);
if not(rp1) then exit;
i:=next[i];
end;
end;
begin
readln(n,m);
for i:=1 to m do
begin
readln(a[i,1],x1,x1,a[i,2],x2,x2);
if (x1='Y') and (x2='N') then
begin
add(a[i,1]+n,a[i,2]+n);
add(a[i,2],a[i,1]);
end;
if (x1='Y') and (x2='Y') then
begin
add(a[i,1]+n,a[i,2]);
add(a[i,2]+n,a[i,1]);
end;
if (x1='N') and (x2='Y') then
begin
add(a[i,1],a[i,2]);
add(a[i,2]+n,a[i,1]+n);
end;
if (x1='N') and (x2='N') then
begin
add(a[i,1],a[i,2]+n);
add(a[i,2],a[i,1]+n);
end;
end;
fillchar(cp,sizeof(cp),0);
ans:='';
q:=0;
for i:=1 to n do
begin
inc(q);
rp1:=true;
rp:=n+i;
work(i);
rp2:=rp1;
inc(q);
rp1:=true;
rp:=i;
work(n+i);
if not(rp1) and not(rp2)
then begin
writeln('IMPOSSIBLE');
halt;
end;
if (rp1) and (rp2) then ans:=ans+'?'
else if rp2 then ans:=ans+'Y'
else ans:=ans+'N';
end;
writeln(ans);
end.