2017多校联合第6次hdu6105Gameia

题意:

有一颗大小为n的树,有两个人A,B可以在树的节点上涂颜色,A涂白色,B涂黑色,B是VIP,所以B在一个节点涂色之后与这个节点相连的节点也会变成黑色,然后B拥有k个可以切除一条边的机会。

题解:

n为奇数必败。这个自己写一写就知道。然后n为偶数的时候,用vis数组记下节点i作为父节点的次数,然后用结构体数组存下i的儿子和i的儿子个数,再去便利i的儿子有没有作为父节点的情况。
这里其实是找这个树中是否存在一个父节点有两个叶子节点的情况,如果存在那就黑色必败,如果不存在,这时候n为偶数,如果存在k可以把它分为n/2份,这时候黑色就可以赢。
有考虑不到的情况。。。。
比如8个点,七个点在一条线上,第四个点有一个叶子节点。然后这种情况我的代码是错误的,(虽然没有这种数据。)

#include<bits/stdc++.h>
using namespace std;
int vis[500+10];
struct bbq
{
    int mount=0;
    int son[500+5];
};
bbq f[500+6];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k,flag=0;
        memset(vis,0,sizeof vis);
        memset(f,0,sizeof f);
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n-1;i++)
        {
            int a;
            scanf("%d",&a);
            vis[a]++;
            f[a].son[f[a].mount++]=i+1;
        }
        if(n%2==1)
        {
            printf("Alice\n");
            continue;
        }
        for(int i=1;i<=n;i++)
        {
            int sum1=0;
            for(int j=0;j<f[i].mount;j++)
            {
                if(!vis[f[i].son[j]])
                   {
                       sum1++;
                   }
            }
            if(sum1>=2)
                flag=1;
        }
        if(k<n/2-1)
            flag=1;
        if(flag)
            printf("Alice\n");
        else printf("Bob\n");
    }
}

题解的思路是从叶子节点开始枚举,如果最小的父节点有两个或两个以上叶子节点,那就黑色必败,如果只有一个,那就切掉,这样一次次切除,看最后是否会剩下两个。(我好菜啊。。。。。。。。)

// {{{
#include <iostream>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <complex>
#include <algorithm>
using namespace std;
// }}}
// #define {{{
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define per(i,a,b) for(int i=(b)-1;i>=(a);--i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
// }}}

const int N = 1e5 + 10;
int T,n,K,par[N],sz[N];

int main(){
    scanf("%d",&T);
    rep(i,0,T){
        scanf("%d%d",&n,&K);
        rep(i,2,n+1) scanf("%d",par + i);
        rep(i,1,n+1) sz[i]=1;
        bool ok=1;
        per(i,1,n+1) ok&=sz[i]<=2,sz[par[i]]+=sz[i]&1;
        puts(n%2==0&&K>=n/2-1&&ok?"Bob":"Alice");
    }
    return 0;
}
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值