zoukankan      html  css  js  c++  java
  • Sequential Nim(CodeForces

    B - Sequential Nim (CodeForces - 1382B)

    题目链接

    算法

    博弈

    时间复杂度O(N)

    1.这道题乍一看以为用Nim博弈直接套用就可以了,结果通过题意发现并不是。题目中要求取石子时只能从下标最小的那一堆开始取,也就是说一堆一堆的取,不能跳着取。

    2.分析完题意,我们知道最后取完最后一堆的人必胜。那么怎么分析谁最后会赢呢?

    如果只有一堆的话,很容易得出第一个人获胜。关键在于如何分析多堆的情况。

    为了方便,我们将每一堆中首先取的人称为先手,然后取的人是后手,下面我们来进行分类讨论:

    • 如果某一堆只有1个石子,那么先手只能取这一个石子。如果还有剩余的石堆,那么此先手在下一堆中将成为后手(因为两个人是轮流取的);如果没有剩余的石堆,那么此先手获胜。
    • 如果某一堆中有若干个石子(超过1个),为了最优,先手有两种取法,要么全取完,要么取走大部分,只剩余一个。前者会使得先手在下一堆中充当后手,后者会使先手在下一堆中充当先手。当然如果没有下一堆了,取完即可,这时先手赢。否则还要继续判断。

    分类讨论后发现,一共就上面两大类情况。那么该怎么做呢?这里是题目的一个难点。

    对于先手,当该石堆中石子个数超过1并且还有其他的石堆时,他可以根据实际情况选择在下一堆中成为先手还是后手。但是当石堆中石子个数为1时他别无选择,只能是在下一堆中成为后手。所以说石子个数为1的石堆为转折点。

    既然当某石堆石子个数大于1时先手可以任意选择在下一堆中他的身份,所以如果还有其他石堆,那么该先手必胜。(因为他掌握着主动权,所以他完全可以根据剩余的石堆数来选择接下来的身份,至于怎么选我们不用考虑)

    当石子个数等于1时,先手变成后手,后手变成先手。

    3.总结一下,我们只需从头判断每一堆的石子的个数,若个数为1,则继续循环,直到循环完。如果循环完了,说明都为1,这时只需判断石堆个数即可;若出现个数不为1的,则先手必胜,跳出循环即可。

    C++代码

    #include<iostream>
    using namespace std;
    const int N = 1e5 + 10;
    int t, n;
    int a[N];
    int main()
    {
        cin >> t;
        while(t--)
        {
            cin >> n;
            for(int i = 0; i < n; i++)
                cin >> a[i];
            int first = 1, second = 0;
            bool flag = false;
            for(int i = 0; i < n; i++)
            {
                if(a[i] == 1)
                {
                    if(first)
                    {
                        first = 0;
                        second = 1;
                    }
                    else
                    {
                        first = 1;
                        second = 0;
                    }
                }
                else
                {
                    if(first)
                        puts("First");
                    else
                        puts("Second");
                    flag = true;
                    break;
                }
            }
            if(!flag)
            {
                if(n % 2 == 1) puts("First");
                else puts("Second");
            }
    
        }
    }
    

    思路来源(注意这里“先手”的定义与思路来源连接里的“先手"定义不同)

  • 相关阅读:
    5款强大的Java Web开发工具
    [Visual Studio] 重置默认设置 还原默认设置
    [Visual Studio] VS2012调试时很慢的解决方案
    SQL 语句与性能之执行顺序
    SQL 语句与性能之联合查询和联合分类查询
    使用SHFB(Sandcastle Help File Builder)建立MSDN风格的代码文档
    循序渐进地代码重构
    博客收藏
    [已解决]:调用 LoadLibraryEx 失败,在 ISAPI 筛选器 "c:WindowsMicrosoft.NETFrameworkv4.0.30319\aspnet_filter.
    [Visual Studio] .vsix项目模板制作
  • 原文地址:https://www.cnblogs.com/KeepZ/p/13752161.html
Copyright © 2011-2022 走看看