zoukankan      html  css  js  c++  java
  • HDU 4664 Triangulation【博弈论】

    一个平面上有n个点(一个凸多边形的顶点),每次可以连接一个平面上的两个点(不能和已经连接的边相交),如果平面上已经出现了一个三角形,则不能在这个平面上继续连接边了。

    现在总共有N个平面,每个平面上都有若干点。(就是有N个相同的游戏同时进行了)。


    想法很单纯,就是计算出每一个平面上游戏的sg函数值,然后求Nim和就哦了。

    sg函数暴力求法:

    一个平面上连接点时,不能连接已经有边的顶点,因为对方只需要再连接一次就可以组成一个三角形了。又所有的边不能相交,因此每连接一条边,就相当于把整个平面上的点划分成了两个部分,在接下来的游戏中,只能单独在两部分里面进行,相当于将一个游戏划分成了两个游戏。因此当前状态x的sg函数值就是两个子游戏的Nim和了。

    即:sg(x) = mex{ sg(i)^sg(x-i-2) }


    这样复杂度很高。但是这道题目有规律,在大数据的范围下,会出现循环,循环长度为34,因此只需要小数据暴力,大数据打表就哦了。


    #include <cstdio>
    #include <cstring>
    typedef long long ll;
    #define N 1002
    bool vis[N];
    int sg[N];
    int a[] = {4,8,1,1,2,0,3,1,1,0,3,3,2,2,4,4,5,5,9,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7};
    int SG(int x) {
        if (sg[x] != -1) return sg[x];
        if (x == 0) return 0;
        if (x == 1) return 0;
        if (x == 2) return 1;
        if (x == 3) return 1;
        memset(vis, false, sizeof(vis));
        for (int i=0; i<x-1; i++) vis[SG(i)^SG(x-i-2)] = true;
        for (int i=0; ;i++) if (!vis[i]) return i;
    }
    int get_sg(int x) {
        if (x <= 100) return sg[x];
        return a[x%34];
    }
    int main() {
        memset(sg, -1, sizeof(sg));
        for (int i=0; i<=100; i++) sg[i] = SG(i);
    
        int T, n, x; scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            int ans = 0;
            while (n--) { scanf("%d", &x); ans ^= get_sg(x); }
            puts(ans ? "Carol" : "Dave");
        }
        return 0;
    }
    


  • 相关阅读:
    如何在SQLite中创建自增字段?
    Windows XP平台下编译boost[1.47及以上]
    智能指针的向下转型
    采用Boost::filesystem操作文件
    CodeSmith访问数据库
    std::string的一些操作
    PDF加入内嵌字体
    悟空和唐僧的对话
    收获和教训的一天配置ds1401
    vxworks的一个changlog
  • 原文地址:https://www.cnblogs.com/riskyer/p/3249312.html
Copyright © 2011-2022 走看看