1 条题解

  • 0
    @ 2025-8-24 21:31:52

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar stone_juice石汁
    敲稀有滴物种石汁qaq

    搬运于2025-08-24 21:31:52,当前版本为作者最后更新于2019-08-11 21:10:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


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

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

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

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

    思路

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

    • 11、小a每次都先下,并且都是下正中心位置。

    • 22、在场的棋子数不超过三颗

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

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

    • 11、小a每次占住正中心位置,毫无疑问这是巨大优势,这时候小a不管下在哪里都可以凑成两颗,而uim则不得不防守。

    • 22、在场的棋子数不超过三颗,这意味着当时的情况一定未分出胜负(所以写什么判断当时是否出现胜负那是完全不必要的)。

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

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

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

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

    • Ⅰ、走边角

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

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

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

    为什么这么说?

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

    如图例:

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

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

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

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

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

    • Ⅱ、走邻边

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

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

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

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

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

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

    如图:

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

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

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

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

    • 特殊情况

    uim走邻边有一种特殊情况

    -O-
    -O-
    -X-
    
    

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

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

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

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

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

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

    其他情况则不明输赢

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

    代码实现

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

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

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

    如果ii为偶数,并且发现输入的是一个XX,就可以直接判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,希望大家都能看懂吧

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

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

    • 1

    信息

    ID
    885
    时间
    1000ms
    内存
    128MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者