[多校2015.01.1012 博弈] hdu 5299 Circles Game

题意:

在无限大的平面内给你n个圆,两个圆之间只可能是包含或者相离

A和B每次选择一个圆,删除这个圆连通它所包含的所有圆

谁不能选择圆删除了,谁就输了

思路:

所有圆可以构造成一棵树,然后按树上SG博弈来做就好了。

树的删边游戏

规则如下:

给出一个有 N 个点的树,有一个点作为树的根节点。

游戏者轮流从树中删去边,删去一条边后,不与根节点相连的部分将被移走。

谁无路可走谁输。

我们有如下定理:

[定理]

叶子节点的 SG 值为 0;

中间节点的 SG 值为它的所有子节点的 SG 值加 1 后的异或和。

重点是这个树的构造,运用排序+dfs的方法!

代码:

#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"map"
#include"vector"
#include"string"
#include"cmath"
using namespace std;
#define N 22222
vector<int>edge[N];
struct node
{
    int x,y,r;
} c[N];
int cmp(node a,node b)
{
    return a.r>b.r;
}
double dis(int a,int b)
{
    return sqrt((c[a].x-c[b].x)*(c[a].x-c[b].x)+(c[a].y-c[b].y)*(c[a].y-c[b].y)*1.0);
}
void go(int x,int k)
{
    int lit=edge[x].size();
    for(int i=0; i<lit; i++)
    {
        int v=edge[x][i];
        double s=dis(v,k);
        if(s+c[k].r>c[v].r) continue;
        go(v,k);
        return ;
    }
    edge[x].push_back(k);
    return ;
}
int dfs(int x)
{
    int lit=edge[x].size();
    if(lit==0) return 0;
    int ans=0;
    for(int i=0; i<lit; i++)
    {
        int v=edge[x][i];
        ans^=dfs(v)+1;
    }
    return ans;
}
int main()
{
    int t;
    cin>>t;
    c[0].x=c[0].y=0;
    c[0].r=100000;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; i++) scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].r);
        sort(c+1,c+1+n,cmp);
        for(int i=0; i<=n; i++) edge[i].clear();
        for(int i=1; i<=n; i++) go(0,i);
        if(dfs(0)==0) puts("Bob");
        else puts("Alice");
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 06:44:37

[多校2015.01.1012 博弈] hdu 5299 Circles Game的相关文章

hdu 5299 Circles Game(博弈)

题目链接:hdu 5299 Circles Game 每个分离的圆都是单独的游戏,Nim值为该圆嵌套中的圆的Nim和,最后加1. #include <cstdio> #include <cstring> #include <vector> #include <set> #include <algorithm> using namespace std; const int maxn = 20005; typedef long long ll; st

[多校2015.01.1002 单调队列] hdu 5289 Assignment

题意: 给你n个人和一个k 问你把这n个人分成多少个连续的子区间,要求区间每个数两两相差绝对值小于k 思路: 我们仅仅只需要对于当前位置,最左边那个和它绝对值相差大于等于k 的位置在哪 假设对于i这个位置,最左边的位置是tep,不存在的话tep=0 那么当且位置的贡献就是 sum[i]=min(i-tep,sum[i-1]+1); 那么对于这个位置怎么求的话,我是使用了两个单调队列 第一次维护递增的,第二次维护递减的. 每次先把不满足的点全部出队,然后记录最大的下标 然后入队 代码: #incl

[多校2015.01.1010 容斥+迭代] hdu 5297 Y sequence

题意: 给你一个n和一个r,求Y序列的第N项是多少. 所谓的Y序列就是,从1开始,去掉能表示成a^b(2<=b<=r)的数,所构成的序列 例如r=2 序列就是:2,3,5,6,7,8,10,11,12,13,14,15,17.... 思路: 我们应该能想到需要一个函数fun(x) 求的是1~x内在Y序列里的数有多少个 这个其实不难,我们可以运用容斥原理,通过63以内的素数进行计算,并且最多做三遍,因为2*3*5*7>63 然后就是一个很神奇的方法了,这个方法特别的秒 就是迭代的方法. 假

【SG博弈】HDU 5299 Circles Game

通道:http://acm.hdu.edu.cn/showproblem.php?pid=5299 题意:n个不相交相切的圆,每次操作删圆及其内部的圆,不能删者败. 思路:建边,然后树上SG即可. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <set> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int MAX_N =

[多校2015.02.1004 dp] hdu 5303 Delicious Apples

题意: 在一个长度为L的环上有N棵苹果树.你的篮子容量是K个苹果. 每棵苹果树上都有a[i]个苹果. 问你从0点出发最少要走多少距离能拿完所有的苹果. 思路: 我们考虑dp,dp[0][i]代表顺时针取i个苹果的最短距离. dp[1][i]代表逆时针取i个苹果的最短距离. 那么设苹果的总是为sum 那么ans=dp[0][i]+dp[sum-i]  (0<=i<=sum) 代码: #include"stdio.h" #include"algorithm"

HDU 5299 Circles Game

转化为树的删边游戏... 树的删边游戏 规则例如以下:  给出一个有 N 个点的树,有一个点作为树的根节点.  游戏者轮流从树中删去边,删去一条边后,不与根节点相连的 部分将被移走.  谁无路可走谁输. 我们有例如以下定理: [定理] 叶子节点的 SG 值为 0; 中间节点的 SG 值为它的全部子节点的 SG 值加 1 后的异或和. Circles Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/6553

计数方法,博弈论(扫描线,树形SG):HDU 5299 Circles Game

There are n circles on a infinitely large table.With every two circle, either one contains another or isolates from the other.They are never crossed nor tangent.Alice and Bob are playing a game concerning these circles.They take turn to play,Alice go

2014多校第十场1004 || HDU 4974 A simple water problem

题目链接 题意 : n支队伍,每场两个队伍表演,有可能两个队伍都得一分,也可能其中一个队伍一分,也可能都是0分,每个队伍将参加的场次得到的分数加起来,给你每个队伍最终得分,让你计算至少表演了几场. 思路 : ans = max(maxx,(sum+1)/2) :其实想想就可以,如果所有得分中最大值没有和的一半大,那就是队伍中一半一半对打,否则的话最大的那个就都包了. 1 #include <cstdio> 2 #include <cstring> 3 #include <st

2014多校第一场A题 || HDU 4861 Couple doubi

题目链接 题意 : 有K个球,给你一个数P,可以求出K个值,(i=1,2,...,k) : 1^i+2^i+...+(p-1)^i (mod p).然后女朋友先取,再xp取,都希望赢,如果女朋友能赢输出YES,否则输出NO 思路 :这个题,在纸上算算差不多就出来结果了,因为要赢,所以一开始必定拿大的,根据规律可以发现最后的那个取余结果不是0就是某个数,所以就看那个数有奇数个还是偶数个即可. 官方题解: 1 #include <stdio.h> 2 #include <string.h&g