[位運算+搜索]下棋

[題目描述]

【問題描述】

 

學習之餘,小秋秋還喜歡進行棋類活動。。。

現在,小秋秋迷上了一個叫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繞暈了.

發佈了45 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章