1. 程式人生 > >【叠代博弈+搜索+剪枝】poj-1568--Find the Winning Move

【叠代博弈+搜索+剪枝】poj-1568--Find the Winning Move

() spa class 勝利 hid iat media gif nes

poj 1568:Find the Winning Move 【叠代博弈+搜索+剪枝】

題面省略。。。

Input

The input contains one or more test cases, followed by a line beginning with a dollar sign that signals the end of the file. Each test case begins with a line containing a question mark and is followed by four lines representing the board; formatting is exactly as shown in the example. The characters used in a board description are the period (representing an empty space), lowercase x, and lowercase o. For each test case, output a line containing the (row, column) position of the first forced win for x, or ‘#####‘ if there is no forced win. Format the output exactly as shown in the example.

Output

For this problem, the first forced win is determined by board position, not the number of moves required for victory. Search for a forced win by examining positions (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), ..., (3, 2), (3, 3), in that order, and output the first forced win you find. In the second test case below, note that x could win immediately by playing at (0, 3) or (2, 0), but playing at (0, 1) will still ensure victory (although it unnecessarily delays it), and position (0, 1) comes first.

Sample Input

?
....
.xo.
.ox.
....
?
o...
.ox.
.xxx
xooo

....
....
....
.... (再加一組特殊樣例) $

Sample Output

#####
(0,1)
#####

大致題意::

    給定一個四乘四的棋盤,面對一個殘局;問先手再下一步是否可以達成最終的勝利;若可以則輸出按順序的坐標最小的那個。

解決思路:

    (我給起的名字是博弈搜索算法,其實是極大極小搜索算法!)

    博弈叠代思想+搜索+剪枝。     思路解釋起來很麻煩,簡單說就是:枚舉先手一步,針對新加的新手一步--然後判斷是否後手無論怎麽下就註定是死局......

註意:

   1、在叠代的過程中,平局也是後手勝,因為題目僅要求先手是否面對的是必贏局! 2、我的博客專欄胡搞裏也有相關的可以瞅瞅!http://www.cnblogs.com/zhazhaacmer/category/1137385.html
帶註釋的題解(第二種check()為超時的判斷局面的函數): 技術分享圖片
 1 char mp[4][5];
 2 int check(int x,int y,char mp[4][5]){   //判定新更改的點(x,y)是否會構成勝利的局面,兩斜/橫/豎
 3    if(x==y&&mp[0][0]!=.&&mp[0][0]==mp[1][1]&&mp[1][1]==mp[2][2]&&mp[2][2]==mp[3][3])
 4         return (mp[0][0]==x?0:1);
 5     if(x+y==3&&mp[0][3]!=.&&mp[0][3]==mp[1][2]&&mp[1][2]==mp[2][1]&&mp[2][1]==mp[3][0])
 6         return (mp[0][3]==x?0:1);
 7     if(mp[x][0]!=.&&mp[x][0]==mp[x][1]&&mp[x][1]==mp[x][2]&&mp[x][2]==mp[x][3])
 8             return (mp[x][0]==x?0:1);
 9     if(mp[0][y]!=.&&mp[0][y]==mp[1][y]&&mp[1][y]==mp[2][y]&&mp[2][y]==mp[3][y])
10             return (mp[0][y]==x?0:1);
11 }
12 /*       !!下面這種判斷是否可以達到結束的局面的方法,時間復雜度高,畢竟把整個圖跑了兩遍!
13  int check1(char mp[4][5]){    //三種返回值,0表示前者,1表示後者,-1表示平局
14     for(int i=0;i<=3;i++){
15        if(mp[i][0]!=‘.‘&&mp[i][0]==mp[i][1]&&mp[i][1]==mp[i][2]&&mp[i][2]==mp[i][3])
16             return (mp[i][0]==‘x‘?0:1);
17     }
18     for(int i=0;i<=3;i++){
19        if(mp[0][i]!=‘.‘&&mp[0][i]==mp[1][i]&&mp[1][i]==mp[2][i]&&mp[2][i]==mp[3][i])
20             return (mp[0][i]==‘x‘?0:1);
21     }
22     if(mp[0][0]!=‘.‘&&mp[0][0]==mp[1][1]&&mp[1][1]==mp[2][2]&&mp[2][2]==mp[3][3])
23         return (mp[0][0]==‘x‘?0:1);
24     if(mp[0][3]!=‘.‘&&mp[0][3]==mp[1][2]&&mp[1][2]==mp[2][1]&&mp[2][1]==mp[3][0])
25         return (mp[0][3]==‘x‘?0:1);
26 
27     for(int i=0;i<=3;i++){    
28         for(int j=0;j<=3;j++){
29             if(mp[i][j]==‘.‘)
30                 return -1;
31         }
32     }
33     return 1;//假設整個棋盤全部布滿,平局就也是後者贏!
34 }
35 */
36 int check_whole(){      //  //判斷全局都是點‘.‘,若是則一定是平局,此種特例不特判必定超時
37     for(int i=0;i<=3;i++){
38         for(int j=0;j<=3;j++)
39             if(mp[i][j]!=.)
40                 return false;
41     }
42     return true;
43 }
44 int ansx,ansy;//記錄第一次下的點的x和y坐標,也就是step=0的時候!
45 
46 bool dfs(int x,int y,int op,int step){//對於op來說,先手X: 0要求必贏,後手1要求不敗即可!
47     char ch = (op==0)?x:o;
48 
49     int val=check(x,y,mp);
50     if(val==op)
51         return true;
52     else if(val==!op)
53         return false;
54 
55         for(int i=0;i<=3;i++){
56             for(int j=0;j<=3;j++){
57                 if(mp[i][j]==.){
58                     mp[i][j]=ch;
59                     if(dfs(i,j,!op,step+1)==false){
60                         mp[i][j]=.;
61                   //  printf("****step=%d****%d,%d ch=%c\n",step,i,j,(op==0)?‘x‘:‘o‘);
62                         if(step==0){
63                             ansx=i;ansy=j;
64                         }
65                         return true;
66                     }
67                     mp[i][j]=.;
68                 }
69             }
70         }
71 
72     return false;
73 }
74 
75 int main(){
76     char ch[2];
77     while(scanf("%s",ch),ch[0]!=$){
78         for(int i=0;i<=3;i++)
79             scanf("%s",mp[i]);
80         if(check_whole()==true)//特判一次!全圖都為點時,不忽略的話註定超時!
81             printf("#####\n");
82         else if(dfs(0,0,0,0)==true)
83             printf("(%d,%d)\n",ansx,ansy);
84         else
85             printf("#####\n");
86     }
87 
88     return 0;
89 }
View Code(頭文件都回家過五一嘍了!QWQ)

【叠代博弈+搜索+剪枝】poj-1568--Find the Winning Move