题目大意:
BAlice有M1块石子,Bob有M2块石子,游戏一开始,所有石头放在树的节点处,除了树根。Alice先移然后两人轮流移动,每次移动只能选择自己的一个石子,而且只能从当前位置移到父亲节点处,游戏过程中允许一个节点处放多个石子。
谁先把自己所有的石子移到树根处谁就失败了,假设两人都是非常聪明,游戏过程中都使用最优策略,给定石子起始位置,要你计算出谁是赢家。
有T组询问 T<=10
树的节点数为N
1<=N<=10000
1<=M1<=10000
1<=M2<=10000
注意0是树根
题解:
这题其实不是想象中的博弈,而是一道比较简单的题目。
不难发现,只要将双方所有石子走到根节点0的路径和求出来然后判断即可。
首先可以弄双向边,然后以0为根构建一颗树,因为0必定为树根(题意)
然后求出每个点的深度记录一下,对于i点走到根节点的步数,为deep[i]-1
然后枚举所有点算Alice跟Bob分别一共能走多少步
当可行步数相同时因为Alice先手所以Bob胜
否则谁大谁胜
代码:
var
check,list,deep:array [0..10001] of longint;
num:array [0..10001,1..2] of longint;
w,next:array [0..20001] of longint;
t,p,q,z,i,j,n,m1,m2:longint;
procedure add(x,y:longint);
begin
inc(z);
w[z]:=y;
next[z]:=list[x];
list[x]:=z;
end;
procedure dfs(now,dep:longint);
var
i:longint;
begin
deep[dep]:=now;
i:=list[dep];
while i>0 do
begin
if check[w[i]]=-1 then
begin
check[w[i]]:=-5;
dfs(now+1,w[i]);
end;
i:=next[i];
end;
end;
begin
readln(t);
while t>=1 do
begin
readln(n,m1,m2);
z:=0;
for i:=0 to n-1 do
begin
list[i]:=0;
check[i]:=-1;
deep[i]:=0;
num[i,1]:=0;
num[i,2]:=0;
end;
for i:=1 to n-1 do
begin
readln(p,q);
add(p,q);
add(q,p);
end;
check[0]:=-5;
dfs(1,0);
for i:=1 to m1 do
begin
read(p);
inc(num[p,1]);
end;
for i:=1 to m2 do
begin
read(q);
inc(num[q,2]);
end;
p:=0; q:=0;
for i:=0 to n-1 do
begin
p:=p+(deep[i]-1)*num[i,1];
q:=q+(deep[i]-1)*num[i,2];
end;
if p>q then writeln('Alice')
else writeln('Bob');
dec(t);
end;
end.