HDU 5299 Circles Game (圆的扫描线+树上SG)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5299


题意:

平面上有n个两两不交的圆,现在有两个人轮流选取圆,每选到一个圆就要把这个圆及其内部的所有圆都删去,最后不能操作的人输,问谁有必胜策略。


分析:

由于圆两两不交,如果根据圆的包含关系建个图,可以得到一个森林,问题转化为树上的SG博弈,复杂度O(nlogn),

建图的时候需要用到圆的扫描线,具体可以搜索HDU3511 Prison Break的题解,

有关树上SG博弈的结论可以参看2009年国家集训队贾志豪的论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》。


代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
typedef double db;
const db eps=1e-6;
const int MAXN=20005;
int sgn(db x)
{
    if(x>eps)return 1;
    if(x<-eps)return -1;
    return 0;
}
db Time;
struct Circle
{
    db x,y,r;
    db getX(int flag)
    {
        return x-flag*r;
    }
    db getY(int flag)
    {
        return y+flag*sqrt(max(r*r-(Time-x)*(Time-x),0.0));
    }
}c[MAXN];
struct Event
{
    db x,y;
    int v,id;
    bool operator < (const Event &t)const
    {
        return sgn(x-t.x)==0 ? v<t.v : x<t.x;
    }
}s[MAXN<<1];
vector<int>e[MAXN];
int p[MAXN],dep[MAXN];
struct node
{
    int id,flag;
    node(){}
    node(int _id,int _flag):id(_id),flag(_flag){}
    bool operator < (const node &t)const
    {
        db y1=c[id].getY(flag);
        db y2=c[t.id].getY(t.flag);
        return sgn(y1-y2)==0 ? flag<t.flag : y1<y2;
    }
};
void build(int n)
{
    memset(dep,0,sizeof(dep));
    for(int i=0;i<=n;i++)e[i].clear();
    for(int i=1;i<=n;i++)
    {
        s[2*i-1].x=c[i].x-c[i].r;
        s[2*i-1].v=1;
        s[2*i].x=c[i].x+c[i].r;
        s[2*i].v=-1;
        s[2*i-1].y=s[2*i].y=c[i].y;
        s[2*i-1].id=s[2*i].id=i;
    }
    sort(s+1,s+2*n+1);
    set<node>Line;
    set<node>::iterator up,down;
    for(int i=1;i<=2*n;i++)
    {
        Time=s[i].x;
        if(s[i].v<0)
        {
            Line.erase(node(s[i].id,1));
            Line.erase(node(s[i].id,-1));
        }
        else
        {
            down=Line.lower_bound(node(s[i].id,1));
            up=down;
            if(down==Line.begin() || up==Line.end())
            {
                e[0].push_back(s[i].id);
                p[s[i].id]=0;
                dep[s[i].id]=1;
            }
            else if((--down)->id == up->id)
            {
                e[down->id].push_back(s[i].id);
                p[s[i].id]=down->id;
                dep[s[i].id]=dep[down->id]+1;
            }
            else
            {
                if(dep[down->id] > dep[up->id])
                {
                    e[up->id].push_back(s[i].id);
                    p[s[i].id]=up->id;
                    dep[s[i].id]=dep[up->id]+1;
                }
                else if(dep[up->id] > dep[down->id])
                {
                    e[down->id].push_back(s[i].id);
                    p[s[i].id]=down->id;
                    dep[s[i].id]=dep[down->id]+1;
                }
                else
                {
                    e[p[down->id]].push_back(s[i].id);
                    p[s[i].id]=p[down->id];
                    dep[s[i].id]=dep[p[down->id]]+1;
                }
            }
            Line.insert(node(s[i].id,1));
            Line.insert(node(s[i].id,-1));
        }
    }
}
int dfs(int u)
{
    int res=0;
    for(int i=0;i<e[u].size();i++)
        res^=dfs(e[u][i]);
    return res+(u!=0);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
        build(n);
        if(dfs(0))printf("Alice\n");
        else printf("Bob\n");
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/quailty/article/details/47781147
今日推荐