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;
}


 

 

posted on 2013-08-09 23:37  you Richer  阅读(236)  评论(0编辑  收藏  举报