zoukankan      html  css  js  c++  java
  • 宽度优先搜索 之 CODE[VS] 1004 四子连棋

    /*
    bfs + hash判重
     
    第一次接触“hash判重”(哈希函数是依据于取余),是一种很好的思想,不过也有小的瑕疵:
    hash判重:
    	棋盘表示:空(0),白(1),黑(2)
    	整个棋盘一共16个格子,可以看成3进制的16位数,将其转化为10进制数,找一个质数取余,利用余数的不同来给棋盘的状态判重。
    	(用质数取余的原因:我不知道为什么用质数取余,但是《算法导论》以及其他地方都推荐用质数取余,应该不会错的。。。)
     
     
    细心一下就会发现,这里面有问题:
    	定义用于取余的质数为y,需要取余的数集为x[],已知: y < max(x[])
    	所以会存在这种情况:x[1]%y == x[2]%y (x[1] != x[2])
    	故:判重结果出现错误。。。
     
    这种担心是对的,但是测试数据出现这种情况的概率很小,所以题目可以AC。
    另,为进一步降低冲突的概率,斌神推荐:可以用两个质数进行取模,两个质数同时取模都相等几乎不可能了
     
     
    (我看了一些资料,发现用于取模的质数还是有很多讲究的,但是暂时先这么取吧。。。)
    对于质数的选取,个人的看法:
    	尽量在x[]的最大值附近取(在保证不爆内存的情况下),这样冲突的概率应该更低一些。
     
    */
      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <cstddef>
      5 #include <iterator>
      6 #include <algorithm>
      7 #include <string>
      8 #include <locale>
      9 #include <cmath>
     10 #include <vector>
     11 #include <cstring>
     12 #include <map>
     13 #include <queue>
     14 #include <stack>
     15 #include <set>
     16 using namespace std;
     17 const int INF = -0x3f3f3f3f;
     18 const int MaxN = 10;
     19 const int modPrime = 3046721; // hash判重时,取余时用的质数,由void getPrime()函数获得。
     20 
     21 int step[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
     22 
     23 struct Node 
     24 {
     25     int stepNum;    // 走的步数
     26     int chessboard[MaxN][MaxN];    // 棋盘状态:空(0),白(1),黑(2)
     27     int now;    // 当前走的棋子是白(1),是黑(2),若是第一次出发(0)
     28     Node()
     29     {
     30         stepNum = 0;
     31         now = 0;
     32     }
     33     int blank[2][2]; // 棋盘空的位置
     34 };
     35 
     36 Node startOff;
     37 bool hashJudge[modPrime];
     38 
     39 // 4个数同时相等,返回true;否则返回false
     40 bool equMpl(const int i1, const int i2, const int i3 , const int i4)
     41 {
     42     if ((i1 != i2) || (i2 != i3) || (i3 != i4) || (i4 != i1))
     43     {
     44         return false;
     45     }
     46     return true;
     47 }
     48 
     49 // 判断是否为目标棋局
     50 bool check(const int chessboard[][MaxN])
     51 {
     52     
     53     for (int i = 0; i < 4; ++i)
     54     {
     55         if (equMpl(chessboard[i][0], chessboard[i][1], chessboard[i][2], chessboard[i][3]))
     56         {
     57             return true;
     58         }
     59         if (equMpl(chessboard[0][i], chessboard[1][i], chessboard[2][i],  chessboard[3][i]))
     60         {
     61             return true;
     62         }
     63     }
     64     if (equMpl(chessboard[0][0], chessboard[1][1], chessboard[2][2], chessboard[3][3]))
     65     {
     66         return true;
     67     }
     68     if (equMpl(chessboard[0][3], chessboard[1][2], chessboard[2][1], chessboard[3][0]))
     69     {
     70         return true;
     71     }
     72     return false;
     73 }
     74 
     75 // hash判重,判断棋局是否已经出现过
     76 bool isUsed(const int chessboard[][MaxN])
     77 {
     78     int sum = 0;
     79     int tmp = 1;
     80     for (int i = 0; i < 4; ++i)
     81     {
     82         for (int j = 0; j < 4; ++j)
     83         {
     84             sum += (tmp*chessboard[i][j]);
     85             tmp *= 3;
     86         }
     87     }
     88     sum %= modPrime;
     89     if (hashJudge[sum])
     90     {
     91         return true;
     92     }
     93     hashJudge[sum] = true;
     94     return false;
     95 }
     96 
     97 // 输出棋局的状态
     98 void output(const int chessboard[][MaxN])
     99 {
    100     for (int i = 0; i < 4; ++i)
    101     {
    102         for (int j = 0; j < 4; ++j)
    103         {
    104             if (chessboard[i][j] == 0)
    105             {
    106                 cout << 'O';
    107                 continue;
    108             }
    109             if (chessboard[i][j] == 1)
    110             {
    111                 cout << 'W';
    112                 continue;
    113             }
    114             cout << 'B';
    115         }
    116         cout << endl;
    117     }
    118 }
    119 
    120 void Solve()
    121 {
    122     queue<Node> que;
    123     que.push(startOff);
    124     while (!que.empty())
    125     {
    126         const Node node = que.front();
    127         que.pop();
    128         if (check(node.chessboard))
    129         {
    130             cout << node.stepNum << endl;
    131             //output(node.chessboard);
    132             break;
    133         }
    134 
    135         for (int i = 0; i < 2; ++i)
    136         {
    137             for (int j = 0; j < 4; ++j)
    138             {
    139                 int x = node.blank[i][0] + step[j][0];
    140                 int y = node.blank[i][1] + step[j][1];
    141                 if ((x >= 0) && (x <= 3) && (y >= 0) && (y <= 3) && (node.chessboard[x][y] != node.now))
    142                 {
    143                     Node nodeTmp;
    144                     for (int i = 0; i < 4; ++i)
    145                     {
    146                         for (int j = 0; j < 4; ++j)
    147                         {
    148                             nodeTmp.chessboard[i][j] = node.chessboard[i][j];
    149                         }
    150                     }
    151                     nodeTmp.chessboard[node.blank[i][0]][node.blank[i][1]] = node.chessboard[x][y];
    152                     nodeTmp.chessboard[x][y] = 0;
    153                     nodeTmp.stepNum = node.stepNum + 1;
    154                     nodeTmp.now = node.chessboard[x][y];
    155                     nodeTmp.blank[0][0] = node.blank[(i + 1) % 2][0];
    156                     nodeTmp.blank[0][1] = node.blank[(i + 1) % 2][1];
    157                     nodeTmp.blank[1][0] = x;
    158                     nodeTmp.blank[1][1] = y;
    159                     
    160                     if (!isUsed(nodeTmp.chessboard))
    161                     {
    162                         que.push(nodeTmp);
    163                     }
    164                 }
    165             }
    166         }
    167     }
    168 }
    169 
    170 
    171 // 找到小于10000000(10^7)的最大质数,作为取余时,用的质数
    172 void getPrime()
    173 {
    174     // 获得棋盘状态最大值(16位全是2的情况)
    175     int maxNum = 1, tmp = 1;
    176     for (int i = 0; i < 16; ++i)
    177     {
    178         maxNum += (2 * tmp);
    179         tmp *= 3;
    180     }
    181     cout << "棋盘状态最大值: " << maxNum << endl;
    182     maxNum %= 10000000;
    183     int cnt = 0;
    184     for (int i = maxNum; i >= 5; --i)
    185     {
    186         bool isPrime = true;
    187         for (int j = 2; j <= sqrt(i); ++j)
    188         {
    189             if (i%j == 0)
    190             {
    191                 isPrime = false;
    192                 break;
    193             }
    194         }
    195         if (isPrime)
    196         {
    197             cout << "取余时,用的质数:"<< i << endl;
    198             break;
    199         }
    200     }
    201 }
    202 
    203 
    204 int main() 
    205 {
    206 #ifdef HOME
    207     freopen("in", "r", stdin);
    208     //freopen("out", "w", stdout);
    209 #endif
    210 
    211     //getPrime();
    212     memset(hashJudge, 0, sizeof(hashJudge));
    213     string str;
    214     int blankPos = 0;
    215     for (int i = 0; i < 4; ++i)
    216     {
    217         cin >> str;
    218         for (int j = 0; j < 4; ++j)
    219         {
    220 
    221             if (str[j] == 'B') 
    222             {
    223                 startOff.chessboard[i][j] = 2;
    224                 continue;
    225             }
    226             if (str[j] == 'W')
    227             {
    228                 startOff.chessboard[i][j] = 1;
    229                 continue;
    230             }
    231             startOff.chessboard[i][j] = 0;
    232             startOff.blank[blankPos][0] = i;
    233             startOff.blank[blankPos][1] = j;
    234             ++blankPos;
    235         }
    236     }
    237     Solve();
    238 
    239 
    240 #ifdef HOME
    241     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
    242     _CrtDumpMemoryLeaks();
    243 #endif
    244     return 0;
    245 }
  • 相关阅读:
    通过C#来加载X509格式证书文件并生成RSA对象
    .NET删除字节数组中的0字节
    让.NET 4.0支持TLS1.2协议
    剖析信用卡 DCC 交易
    Python私有变量
    Python中类的定义
    SQL join中on与where区别
    Python私有函数和公开函数
    Python实现装饰模式的一段代码
    Python的sorted函数应用
  • 原文地址:https://www.cnblogs.com/shijianming/p/5003713.html
Copyright © 2011-2022 走看看