题意:
有一颗大小为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;
}