题目链接
题目大意:
给定一棵树,然后Alice和Bob进行博弈,首先Alice选择一个点染色,然后Bob可以将这个点的子节点或者他的祖先进行染色,已经染色的顶点不能再次到达,谁不能动了谁就输了。
解题思路:
想题的时候先把树变成图,将本节点和其祖先连接起来(无向边),所以就是图上的匹配问题(就是在图上找出边的子集,使这些边没有公共顶点)。最大匹配就是找出的边数最多,完美匹配就是所有顶点都属于其中一个边。
结论:如果最大匹配等于完美匹配就是Bob赢,否则就是Alice赢。
证明:
假设现在已经是最大匹配等于完美匹配,因为是匹配,每条边都有两个顶点(v11,v12),(v21,v22)…,所以每个顶点都属于一个匹配,所以不管Alice选择哪个顶点,Bob只要选与他匹配的顶点就可以了,然后Alice再选择一个与B选择相连的顶点,Bob再选择其匹配的点,以此类推,所以就是Bob赢。
假设现在最大匹配不等于完美匹配,就是有至少一个顶点没有被匹配,则Alice先选取一个未匹配的点,Bob就只能选择已经被匹配的点了,如果Bob也能选择一个未匹配,则这两个点会构成一个新的匹配,就与最大匹配定义矛盾。如果bob在后续第k次选择中选到了未匹配的点,则这个点可以与Alice的第k次选择的点进行匹配,则可以往前递推到最前面,发现会构成一条新的匹配,一样与最大匹配矛盾。
如果按思路这样建图则图太大的了,所以就在树上进行匹配。
定义dp[u]为以u为根的子树这些点中所有未匹配的点。
1.如果u是叶子节点,dp[u]=1
2.如果u不是叶子节点,则对所以儿子的未匹配数求和为D,如果D>0,则表示后代节点有未匹配,所以用这个点去匹配,dp[u]=D-1。如果没有未匹配点,则u点就为未匹配点,则dp[u]=1。
实验代码:
#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=2e5+10;
struct E{
int to,nxt;
E(){};
E(int t1,int n1)
{
to=t1;
nxt=n1;
}
}e[maxn];
int head[maxn],tot;
void adde(int u,int v)
{
e[++tot]=E(v,head[u]);
head[u]=tot;
}
int dp[maxn];
int dfs(int u,int fa)
{
bool leaf=true;
for (int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if (to==fa)
continue;
leaf=false;
dp[u]+=dfs(to,u);
}
if (leaf)
dp[u]=1;
else
{
if (dp[u]>0)
dp[u]--;
else
dp[u]=1;
}
return dp[u];
}
int main()
{
int n,t1,t2;
cin>>n;
for (int i=1;i<n;i++)
{
scanf("%d%d",&t1,&t2);
adde(t1,t2);
adde(t2,t1);
}
if (dfs(1,1)==0)
cout<<"Bob";
else
cout<<"Alice";
return 0;
}