问题 F: Removing Coins(博弈,树的直径)

问题 F: Removing Coins

时间限制: 1 Sec  内存限制: 128 MB
提交: 35  解决: 15
[提交] [状态] [命题人:admin]

题目描述

Takahashi and Aoki will play a game on a tree. The tree has N vertices numbered 1 to N, and the i-th of the N−1 edges connects Vertex ai and Vertex bi.
At the beginning of the game, each vertex contains a coin. Starting from Takahashi, he and Aoki will alternately perform the following operation:
Choose a vertex v that contains one or more coins, and remove all the coins from v.
Then, move each coin remaining on the tree to the vertex that is nearest to v among the adjacent vertices of the coin's current vertex.
The player who becomes unable to play, loses the game. That is, the player who takes his turn when there is no coin remaining on the tree, loses the game. Determine the winner of the game when both players play optimally.

Constraints
·1≤N≤2×105
·1≤ai,bi≤N
·ai≠bi
·The graph given as input is a tree.

输入

Input is given from Standard Input in the following format:

N
a1 b1
a2 b2
:
aN−1 bN−1

输出

Print First if Takahashi will win, and print Second if Aoki will win.

样例输入

复制样例数据

3
1 2
2 3

样例输出

First

提示

Here is one possible progress of the game:
·Takahashi removes the coin from Vertex 1. Now, Vertex 1 and Vertex 2 contain one coin each.
·Aoki removes the coin from Vertex 2. Now, Vertex 2 contains one coin.
·Takahashi removes the coin from Vertex 2. Now, there is no coin remaining on the tree.
·Aoki takes his turn when there is no coin on the tree and loses.

 

 

题意:

给定一棵树,树上每个节点初始时有一个硬币。每次操作可以选择一个硬币数大于0的节点u,拿走u上的所有硬币,然后其它所有节点上的硬币向u的方向移动一条边的距离。两个人轮流操作,不能移动的人输。

 

思路:

可以发现,我们只需关心节点上是否有硬币,不需要关系硬币的数量。

删掉的点有两种情况
1. 不是叶子节点,这可以看做把树的所有叶子节点都删掉,树的直径长度减2。
2. 是叶子节点,如果是直径的端点,则直径长度减1,如果不是直径的端点,则直径长度减2。

 

至于为什么和直径有关系,因为每次相当于删掉一层叶子,那你删删删,最后肯定会在直径上剩下点的,因为它最长嘛

 

 

可以发现直径只能减小1或2,那么(可以找规律,也可以sg打表,总之,这部分就是一个基础的nim博弈咯)

得到的结果是如果树的直径%3==2那么second,否则first

 

 

链接、、、

得到了个两次bfs得直径的代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+7;
int head[maxn],tot = 1;
int Next[maxn<<1],to[maxn<<1];
void add(int u,int v){
    to[tot] = v,Next[tot] = head[u];
    head[u] = tot++;
}
int n;
int deep[maxn];
int bfs(int s){
    queue<int> Q;
    memset(deep,0,sizeof deep);
    deep[s] = 1;
    Q.push(s);
    int ans = s;
    while(!Q.empty()){
        int u = ans = Q.front();
        Q.pop();
        for(int i=head[u];i;i=Next[i])if(!deep[to[i]]){
            deep[to[i]] = deep[u]+1;
            Q.push(to[i]);
        }
    }
    return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
	}
	int cnt = deep[bfs(bfs(1))];
	printf("%s\n",cnt%3==2?"Second":"First");
	return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值