Gameia(树上博弈,想法题)

原题: HDU 6105

题意:

n个点的树,A和B依次(A先)选择一个没有被涂色的点涂色,A为白色,B为黑色,B每涂一个点,会将这个点周围(直接相连的点)变成黑色。B有k次删边操作。

解析:

对单链分析:只有当链长为2时,B才能赢,非2使都是A赢

对树分析:
Gameia(树上博弈,想法题)_第1张图片
所以大胆猜想:只要有一个分支存在节点数大于或小于2,那么A就必胜。

所以,首先判断n是否为偶数,B的k次机会能不能将n剪成一段一段2。

接下来就是从叶子开始一段一段删除,用度维护就可以了。

#include
using namespace std;

set<int> fa[509];
set<int>::iterator it;
int di[509];
bool vis[509];

int main(){
    int t;scanf("%d",&t);
    while(t--){
        memset(di,0,sizeof(di));
        memset(vis,0,sizeof(vis));
        int n,k;scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)fa[i].clear();
        for(int i=2,tmp;i<=n;i++)scanf("%d",&tmp),
            di[tmp]++,di[i]++,fa[i].insert(tmp),fa[tmp].insert(i);

        if(n%2||n/2-1>k){printf("Alice\n");continue;}

        queue<int>Q;
        for(int i=1;i<=n;i++)if(di[i]==1)Q.push(i);

        int cant=0;
        while(!Q.empty()){
            int id=Q.front();Q.pop();
            if(fa[id].empty()&&!vis[id]){cant=1;break; }
            vis[id]=1;
            int u=*fa[id].begin();
            vis[u]=1;
            fa[u].erase(id);di[u]--;
            for(it=fa[u].begin();it!=fa[u].end();it++){
                int to=*it;
                fa[to].erase(u);
                di[to]--;
                if(di[to]==1)Q.push(to);
                if(di[to]==0){cant=1;break; }
            }
        }
        if(cant)printf("Alice\n");
        else printf("Bob\n");
    }
}

你可能感兴趣的:(想法题,博弈)