I. Game on Plane(SG函數 博弈論)

題目鏈接

題目描述

給你n個節點的凸包(未連線),每次選擇兩個點連一條線,不能與之前出現的線有相交。當出現一個凸包的時候遊戲結束

誰最後無法移動了就輸了,現在問 是先手必勝還是後手必勝。

類似題:HDU4664 Triangulation  

HDU描述的是當出現一個三角形時 遊戲結束。其實是一個意思,HDU的範圍大一點  涉及循環節。

做法:SG函數。如果你是第一次聽說SG函數。看鏈接:知乎

而對於這題的分析呢。

每一個點集都可以被一條直線分割成一個包含兩部分的子局面,根據SG函數從前往後推

那麼對於當前局面SG(x),它的後繼局面爲 任選兩個點連接後,得到的局面是被該線分割成兩部分,如果下一個人在這條線的兩個端點任意一個出發再連一條線,則下下個人就可以連成三角形使得遊戲結束,因此下一個人必不會再從這兩個端點連線。因此後繼局面爲sg(i)與sg(x-i-2)  [0<=i<=x-2]

即得到sg函數爲:    SG(X)=mex{sg(i)^sg(x-i-2)}  [0<=i<=x-2]

對於GYM的這道題  直接推SG數組即可。

對於HDU 的打表找循環節

由於數據的n很大,打表出前1000項觀察可以得到循環節。。。打表

代碼參考來自:博客  

 

/*
因爲一條直線把當前局面分割成兩個子局面,
i-2是連接完直線後剩下的點,所以兩個子局面的異或就是sg[j]^sg[i-2-j]
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=5010;
int sg[maxn],s[maxn];
 
void SG()
{
    sg[1]=0,sg[2]=1;
    for(int i=3;i<=5000;i++){
        memset(s,0,sizeof(s));
        for(int j=0;j<=i-2;j++) //所有子局面 
            s[(sg[j]^sg[i-2-j])]=1;
        
        for(int j=0;;j++){
            if(!s[j]){
                sg[i]=j; break;
            }
        }
    }
}
int main()
{
    SG();
    int t; scanf("%d",&t);
    while(t--){
        int n; 
        scanf("%d",&n);
        if(sg[n]) puts("First");
        else puts("Second");
    }
    return 0;
}

HDU 題 代碼參考:博客

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
const int MAXN = 1000 + 10;
int vis[MAXN];
int SG[MAXN];
int mex(int x)
{
    if(SG[x] != -1)
        return SG[x];
    memset(vis, 0, sizeof(vis));
    for(int i=0;i<=x-2;i++)
        vis[mex(i) ^ mex(x-2-i)] = 1;
    for(int i=0;;i++) if(!vis[i])
    {
        SG[x] = i;
        break;
    }
    return SG[x];
}
int main()
{
    memset(SG, -1, sizeof(SG));
    for(int i=0;i<200;i++)
        SG[i] = mex(i);
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, x;
        scanf("%d", &n);
        int ans = 0;
        for(int i=0;i<n;i++)
        {
            int x;
            scanf("%d", &x);
            if(x < 100) ans ^= (SG[x]);
            else
            {
                x -= 60;
                x %= 34;
                ans ^= SG[x + 60];
            }
        }
        if(ans) printf("Carol\n");
        else printf("Dave\n");
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章