zoukankan      html  css  js  c++  java
  • 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");
    }

  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477102.html
Copyright © 2011-2022 走看看