Jzoj5674 香槟

有一棵 n 个节点的树,初始时所有节点都为空。Alan 和 Bob 在树上玩游戏,双方轮流进行,Alan先手。每轮中,Alan 可以选择一个空节点 x,在 x 上放一个波澜哥;Bob 每轮可以选择一个空节点 y,将 y 节点以及所有与 y 相邻的节点上都放置一个面筋哥。可能存在节点既有波澜哥,又有面筋哥。当所有节点非空时,游戏结束。

由于面筋哥比较得劲,Alan 和 Bob 认为如果一个节点上有面筋哥,那么该节点是“石灰”的。如果游戏结束时,所有节点都是“石灰”的,Bob 取得胜利;否则,Alan 取得胜利。

Bob 求胜心切,会趁 Alan 不注意切开一些树边。Bob 可以在任意时刻执行切边操作,包括游戏开始前,每回合 Alan 操作前,自己操作前,自己操作后,以及游戏结束后。不过谨慎起见,Bob 不会切边超过 K 条。   

求双方都是最优决策的情况下,谁会取得胜利。

是一个非常奇妙的结论题

我们手玩一下发现一个问题,如果一个联通块大小不为2,那么一定是Alan胜利,下面给出了详细证明:


所以,我们只需要对树做一个完美匹配,让后看看k是否大于n/2-1就行了

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 500010
using namespace std;
int n,k,h[N],f[N],cnt;
struct edge{ int v,nt; } G[N<<1];
inline void adj(int x,int y){
	G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
	G[++cnt]=(edge){x,h[y]}; h[y]=cnt;
}
inline void dfs(int x,int p){
	f[x]=1;
	for(int v,i=h[x];i;i=G[i].nt)
		if((v=G[i].v)!=p){
			dfs(v,x);
			if(f[v]<0){ f[x]=-1; return; }
			f[x]-=f[v];
		}
}
int main(){
	freopen("shampagne.in","r",stdin);
	freopen("shampagne.out","w",stdout);
	scanf("%d%d",&n,&k);
	if((n&1)||(k<(n-1>>1))) return 0&puts("Alan");
	for(int x,y,i=1;i<n;++i){
		scanf("%d%d",&x,&y);
		adj(x,y);
	}
	dfs(1,0);
	if(f[1]) puts("Alan"); else puts("Bob");
}

转载于:https://www.cnblogs.com/Extended-Ash/p/9477102.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值