zoukankan      html  css  js  c++  java
  • POJ 1970 The Game (DFS)

    题目链接http://poj.org/problem?id=1970

    题意:

      有一个19 × 19 的五子棋棋盘,其中“0”代表未放入棋子,“1”代表黑色棋子,”2“代表白色棋子,如果某方的棋子在横,纵,斜这四个方向的连子数(连着的棋子数)恰好为5,那么此方就可以获胜。给你某一刻棋盘上的棋子状态,问你在此刻是哪一方获胜,亦或是平局,平局时仅输出“0”;如果是黑色方获胜,那么输出“1“,白色方获胜输出“2”,并且在第二行输出五连子最左边的棋子的坐标,如果在纵方向五连子,那么输出最上面的那个棋子的坐标。

    思路:

      首先,对于一个棋子来说,它可以和八个方向的棋子连在一起形成连子,但是这里并用不着对棋子的八个方向进行搜索,因为八个方向实质上可以认为是四个方向,即只需对某个棋子的四个方向进行搜索就OK 了,方向的选择也会影响到程序的复杂性,这里的做法是选择一个当前棋子作为起点(0,0),对这个棋子的”“右上”(-1,1),“右”(0,1),“右下”(1,1),“下”(1,0)这四个方向进行搜索,原因是如果这四个方向能找到五连子,那么作为起点的棋子的坐标即是题目要求的最左边的棋子的坐标,可以降低程序复杂性。方向确定了,搜索的状态就确定了,对于每个棋子有四个状态,所以又需要一个辅助数组来标记棋子的某个状态是否已被搜索过,用一个三维数组visit[i][j][k]代表坐标为(i, j)的棋子其k方向是否已被搜索过,k取值为1~4。然后从左到右、从上到下遍历图,分别从四个方向搜索统计就好了。

      由于“右上”方向在搜索中的特殊性,所以这里要解释一些东西。在往“右上”方向搜索的过程中,如果一个棋子的“右上”方向没被搜索过,那么应该尽可能的往这个方向搜索(即使这个方向的其他棋子之前已被搜索过了,这里仍然要进行搜索)。

    比如:

    0 0 0 0 1...

    0 0 0 1 0...

    0 0 1 0 0...

    0 1 0 0 0...

    1 0 0 0 0...

    ...

    首先搜索到的肯定是第一行的”1“,可知连子数为 1个, 但此时并不满足; 再搜索第二行的“1”,此时第一行的1虽然已经搜索过了,但是还需要再搜索一遍,可得连子数为2个; 当搜索到第三行的"1"时,上面的两个"1"仍然要进行搜索统计,可得连子数为3个......底下的两个“1”也是同理,虽然这里可以用记忆化,但是由于搜索树的层数并不深,所以影响不大。

    然后当“右上”方向的延伸结果为5时,这里还需要判断“右上”这个方向的反方向(即右下)有没有一样的棋子(否则会出现6连子,不符合题意),之所以要判断“右上”的反方向是否有多余的棋子,是因为位于“右下”的棋子搜索顺序在当前棋子之后,所以“右下”若有相同的棋子,有可能使得本来的5连子形成6连子,但是“右”的反方向“左”、“右下”的反方向“右上”、"下"的反方向“上”,这三个反方向上的棋子的搜索顺序都在当前棋子之前,不用考虑是否会出现这个现象。

    代码:

     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <stack>
     7 #include <queue>
     8 #include <algorithm>
     9 #include <string>
    10 
    11 typedef long long LL;
    12 using namespace std;
    13 const int MAXN = 19;
    14 const int stepX[] = {0, -1, 0, 1, 1};//四个方向
    15 const int stepY[] = {0, 1, 1, 1, 0};
    16 int visit[MAXN + 3][MAXN + 3][7];//visit[i][j][k]表示位于[i][j]位置的棋子的k方向是否已被搜索过
    17 int map[MAXN + 3][MAXN + 3];//存图
    18 int cnt;
    19 
    20 void DFS(int x, int y, int id, int dire) {//x,y为坐标,id为1或者2,dire代表方位,即确定方位的进行搜索
    21     visit[x][y][dire] = 1;
    22     int nex = x + stepX[dire], ney = y + stepY[dire]; 
    23     if(map[nex][ney] == id){
    24         ++cnt;//统计连子数
    25         DFS(nex, ney, id, dire);
    26     }
    27 }
    28 
    29 int main() {
    30     //freopen("input", "r", stdin);
    31     int t;
    32     scanf("%d", &t);
    33     while(t--) {
    34         memset(visit, 0, sizeof(visit));
    35         memset(map, 0, sizeof(map));
    36         cnt = 0;
    37         for(int i = 1; i <= 19; i++) {
    38             for(int j = 1; j <= 19; j++) {
    39                 scanf("%d", &map[i][j]);
    40             }
    41         }
    42         int leftX = -1, leftY = -1;//五连子最左边棋子的坐标
    43         int win = 0;//获胜的标志
    44         for(int i = 1; i <= 19; i++) {
    45             for(int j = 1; j <= 19; j++) {
    46                 if(!map[i][j]) continue;
    47                 for(int k = 1; k <= 4; k++) {
    48                     if(!visit[i][j][k]) {
    49                         cnt = 1;
    50                         DFS(i, j, map[i][j], k);
    51                         if(cnt == 5 && map[i - stepX[k]][j - stepY[k]] != map[i][j]) {//判断是否为五连子且考虑反方向是否会造成六连子
    52                             win = map[i][j], leftX = i, leftY = j;
    53                         }
    54                     }
    55                 }
    56             }
    57         }
    58         printf("%d
    ", win);
    59         if(win) printf("%d %d
    ", leftX, leftY);
    60     }
    61     return 0;
    62 } 
  • 相关阅读:
    docker-compose
    Cassandra
    npm常用命令
    k8s linux win10
    wsl2 docker 迁移
    docker http 代理
    mysql查看当前所有的数据库和索引大小
    mybatis 遍历list拼接 or查询
    es head crud
    nginx 代理转发mysql
  • 原文地址:https://www.cnblogs.com/Ash-ly/p/5712114.html
Copyright © 2011-2022 走看看