题解 P1917 【三子棋II】
stone_juice石汁 · · 题解
瞟了一眼题解的做法,感觉都把这道题做麻烦了。
不需要花里胡哨的双重
并且只需要
那么怎么做到这种操作的 O_O?
思路
首先,注意题目中给了两个信息:
我不知道是不是有人没注意到这两个信息。这直接决定了思路的繁简 和 代码的长短。
我们来分析一下这两个信息:
那么,江南老赌手石汁教你如何下三子棋,保证不输的那种。
由于小a每次都会站中间,所以我们直接默认中间是
很明显,在只有一颗棋子时,完全判断不出胜负。
我们可以把这张图看成对称的,那么现在,uim就只有两种选择。
- Ⅰ、走边角
也就是走四个角的位置。这样走无疑是很明智的,因为这么一走,uim就可以控制三条线。
如果uim够聪明,这样走,基本上小a就没戏了。
但是如果小a也够聪明,小a也不会输掉。
为什么这么说?
首先,小a在这种情况下必定会再下一颗棋子。只要它不下
如图例:
此时,uim挡住了小a的进攻,并且又控制住了一条边。
小a很可怜了,只能走淡蓝色格子来凑成三颗,但很明显,它要走两步才能凑足。
但是,
当然,如果uim智商下线,小a也有可能会赢。所以完全猜不透到底是平了还是谁赢了。
总结:uim第二颗走边角,完全不知道结果。
- Ⅱ、走邻边
这里所指的邻边,就是排除四个边角,相邻
那么想想,uim走邻边会发生什么。
走邻边,意味着uim这颗棋子只能控制住两条边,如下图。
那么此时,小a只要不走
理所当然地,uim必然会再出一颗棋子去防守,并且又控制住一条边。
但是这完全无济于事,就算如此,小a还是有三条可行线路可以让他连到
如图:
其中打
uim可以堵,但堵得住一个,堵不住两个啊。所以uim会输。
在小a很菜的情况下,可能会不知道谁胜谁负,但是题面中写了这么一句话:以最佳方案下棋,无论对手怎么下,自己必胜
所以,只要有自己必胜的方案就可以了。刚刚无疑满足了这种情况
- 特殊情况
uim走邻边有一种特殊情况
-O-
-O-
-X-
图丢了就不弄图了 (其实想偷懒QAQ)
虽然我们上面提到过,小a不可能会这么下,但是要是数据里有这种情况,就必须特判。但问题是数据并没涉及到这种情况所以我就没写上去了
总结:除特殊情况,uim第二颗走邻边,小a必赢。
在加上落子数不可能超过三颗,也就是uim最多落一颗子。
综合上面所有条件,最后的最后,所有情况化为一句话:
只要uim敢下邻边,那他必输
其他情况则不明输赢
你看,玩这个游戏是不是可以保证不输QAQ,你先手必赢,你后手必不会输。
代码实现
呼,说了这么多,结果结论只有两句话....
我们只需要判断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,希望大家都能看懂吧
如果有什么不懂得地方可以留言,我有时间必会看的。
看我这么苦的份上,是不是应该....