题解 P1917 【三子棋II】

· · 题解

瞟了一眼题解的做法,感觉都把这道题做麻烦了。

不需要花里胡哨的双重for枚举每个点,也不需要什么数组

并且只需要8行就可以写完。

那么怎么做到这种操作的 O_O?

思路

首先,注意题目中给了两个信息:

我不知道是不是有人没注意到这两个信息。这直接决定了思路的繁简 和 代码的长短。

我们来分析一下这两个信息:

那么,江南老赌手石汁教你如何下三子棋,保证不输的那种。

由于小a每次都会站中间,所以我们直接默认中间是O

很明显,在只有一颗棋子时,完全判断不出胜负。

我们可以把这张图看成对称的,那么现在,uim就只有两种选择。

也就是走四个角的位置。这样走无疑是很明智的,因为这么一走,uim就可以控制三条线。

如果uim够聪明,这样走,基本上小a就没戏了。

但是如果小a也够聪明,小a也不会输掉。

为什么这么说?

首先,小a在这种情况下必定会再下一颗棋子。只要它不下X的对角线位,那么uim在下一步必须防守。

如图例:

此时,uim挡住了小a的进攻,并且又控制住了一条边。

小a很可怜了,只能走淡蓝色格子来凑成三颗,但很明显,它要走两步才能凑足。uim肯定不会给他这个机会

但是,uim也一直处于堵小a旗子的状态,导致他根本没机会凑足三颗,除非小a太傻了。

当然,如果uim智商下线,小a也有可能会赢。所以完全猜不透到底是平了还是谁赢了。

总结:uim第二颗走边角,完全不知道结果。

这里所指的邻边,就是排除四个边角,相邻O的方格。

那么想想,uim走邻边会发生什么。

走邻边,意味着uim这颗棋子只能控制住两条边,如下图。

那么此时,小a只要不走X的对边位置,小a就凑成了两连颗。

理所当然地,uim必然会再出一颗棋子去防守,并且又控制住一条边。

但是这完全无济于事,就算如此,小a还是有三条可行线路可以让他连到3

如图:

其中打 * 号的,代表着两种可行线路的重叠部位。只要小a落子此处,必然会形成双2局面。

uim可以堵,但堵得住一个,堵不住两个啊。所以uim会输。

在小a很菜的情况下,可能会不知道谁胜谁负,但是题面中写了这么一句话:以最佳方案下棋,无论对手怎么下,自己必胜

所以,只要有自己必胜的方案就可以了。刚刚无疑满足了这种情况

uim走邻边有一种特殊情况

-O-
-O-
-X-

图丢了就不弄图了 (其实想偷懒QAQ)

虽然我们上面提到过,小a不可能会这么下,但是要是数据里有这种情况,就必须特判。但问题是数据并没涉及到这种情况所以我就没写上去了

总结:除特殊情况,uim第二颗走邻边,小a必赢。

在加上落子数不可能超过三颗,也就是uim最多落一颗子。

综合上面所有条件,最后的最后,所有情况化为一句话:

只要uim敢下邻边,那他必输

其他情况则不明输赢

你看,玩这个游戏是不是可以保证不输QAQ,你先手必赢,你后手必不会输。

代码实现

呼,说了这么多,结果结论只有两句话....

我们只需要判断uim是否下邻边就行了对吧?

很简单,直接用一层for1跑到9,每次输入一个字符

如果i为偶数,并且发现输入的是一个X,就可以直接判uim负了

如果没有出现上述情况,输出“不知道”即可。

先上一个可读性比较高的代码:

#include<bits/stdc++.h>
using namespace std;

int ans;
char x;
bool pd; //pd:判断,用于判断uim是否输了 

int main()
{
    for(int i = 1; i <= 9; i ++)
    {
        scanf("%c", &x);
        if(x == 'X' && !(i % 2))pd = true; //此时,uim已经输了 
        if(x == '-') ans ++;
        //由于我们还要输出棋子个数,我们则记录空格个数,用9-空格个数就知道棋子个数了 
    }

    if(pd == true)
        cout << "xiaoa will win." << endl << 9 - ans;
    else 
        cout << "Dont know." << endl << 9 - ans;
    return 0;
}

再上我之前说过的8行代码

(并且格式是标准的)

#include<bits/stdc++.h>
int ans, x, pd;
int main(){
    for(int i = 1; ~scanf("%c", &x); i ++)
        if(x == 'X' && !(i % 2)) pd = true;
        else if(x == '-') ans ++;
    std::cout << (pd ? "xiaoa will win." : "Dont know.") << std::endl << 9 - ans;
}

后记

这篇题解写的耗时有点久了,还要专门去配图A.A,希望大家都能看懂吧

如果有什么不懂得地方可以留言,我有时间必会看的。

看我这么苦的份上,是不是应该....