[题目描述]
【问题描述】
学习之余,小秋秋还喜欢进行棋类活动。。。
现在,小秋秋迷上了一个叫tic-tac-toe的游戏。。(这种诡异的名字?原题如此)。
这个游戏是两个人轮流在4*4的格子中放棋子,一个人放满了一行或一列或一个对角线就算赢。
现在,小秋秋用X先手,已经下过许多步了。他想知道自己现在是否有必胜策略,以及最小的字典序走法。
【输入文件】
输入有多组数据。
需要你求的数据以’?’开头,然后是一个4*4的矩阵,’.’代表空,’x’代表小秋秋的棋子,’o’代表小秋秋对手的棋子。
输入文件以’$’结束。
【输出文件】
对于每组数据输出一行,若有必胜策略,输出(x,y)表示字典序最小的走法是下到(x,y)(0<=x,y<4)。若无必胜策略,输出#####
[题解]
这道题是一道红果果的搜索题= =.
很简单的最大最小剪枝,我用位运算把棋盘压到一个longint里了.
hi函数是system库的标准函数,返回值是输入的二进制的前半部分.
附上我冗长的代码= =:
program chess;
type
int=longint;
board=int;
var
i,j,m,n,nx,np:int;
k:board;
a,b,aa,c:array[1..16]of int;
ch:char;
ok:boolean;
st:string;
procedure push(var p:board;ch:char;x:int);
begin
if ch='.'then exit;
if upcase(ch)='X'then begin p:=p or(a[x]);inc(nx);end
else begin p:=p or(b[x]);inc(np);end;
end;
function dfs(p:board;x:int;q:int):int;var i,j:int;k:int=0;//true==q win
begin
if(hi(p)+lo(p)=1<<16-1)then exit(-1);
for i:=1 to 10 do begin
if aa[i]and p=aa[i]then exit(0);
if aa[i]and hi(p)=aa[i]then exit(0);
end;
for i:=1 to 16 do if(p and c[i]=0)then begin
if q=1 then j:=dfs(p+a[i],i,0)else j:=dfs(p+b[i],i,1);
if j=0 then exit(1);if j=-1 then k:=-1;
end;
exit(k);
end;
begin
assign(input,'chess.in');reset(input);
assign(output,'chess.out');rewrite(output);
for i:=1 to 16 do begin a[i]:=1<<(i-1);b[i]:=a[i]<<16;c[i]:=a[i]or b[i];end;
for i:=1 to 4 do aa[i]:=(1<<4-1)<<(4*(i-1));
for i:=1 to 4 do aa[5]:=aa[5]or a[i*4];
for i:=6 to 8 do aa[i]:=aa[i-1]>>1;
for i:=1 to 4 do begin
aa[9]:=aa[9]or a[(i-1)<<2+i];
aa[10]:=aa[10]or a[i*4-4+(4-i+1)];
end;
while not seekeof do begin
readln(ch);k:=0;ok:=false;nx:=0;np:=0;
if ch='$'then break;
for i:=1 to 4 do begin
for j:=1 to 4 do begin
read(ch);push(k,ch,4*(i-1)+j);
end;
readln;
end;
if(nx<4)or(np<4)then begin
writeln('#####');
continue;
end;
for i:=1 to 16 do if(c[i]and k=0)and(dfs(k+a[i],i,0)=0)then begin
if i and 3=0 then j:=3 else j:=i and 3-1;
writeln('(',(i-1)div 4,',',j,')');ok:=true;
break;
end;
if not ok then writeln('#####');
end;
close(input);close(output);
end.
被0和1绕晕了.