NOIP2012提高组Day2 第3题 疫情控制 解题报告

疫情控制

题目描述

NOIP2012提高组Day2 第3题 疫情控制 解题报告_第1张图片

样例输入

NOIP2012提高组Day2 第3题 疫情控制 解题报告_第2张图片

样例输出

这里写图片描述

题解

首先我们分析一下题目,可以发现,所有军队可以同时移动,所以多个军队移动的代价等于所有军队移动时间的最大值。题目就是让我们使最大值最小,从此,我们便会自然而然地想到二分。

我们二分军队移动时间的限制 mid ,不难发现,军队当然是走地越上越好(这里的“上”指靠近根节点的程度),这里使用倍增算法向上拓展。如果首都可以驻扎军队,那我们只需要把所有军队在时间限制内,走到最上的点,查看一下所有叶节点能否被覆盖即可。但是现实是残酷的,首都并不能驻扎军队,那我们该怎么办呢?

我们考虑把军队分成两类,第一类是不可以走到根节点的,第二类是可以走到根节点的。那我们现在就是用第二类去匹配那些叶节点不能全部被覆盖的子树(这里的子树指以根节点的儿子为根的树)。

我们先用第一类来判断对于每一颗子树的全部叶节点能否全部被覆盖。(递归判断)
然后我们将那些叶子节点不能全部覆盖的子树记录下来,并把子树的根到根节点的距离记录下来(设其数组为 dis )。After that,我们将第二类的军队到达根节点后的剩余时间也记录下来(设其数组为 time )。

现在我们的任务就变成了用较小的 time 尽量匹配较大的 dis ,此方法类似于田忌赛马。唯一和田忌赛马不同的是,对于每一个军队都可以直接匹配它所属的子树。当我们要调用每一个军队时,看一下匹配其所属军队更优还是匹配枚举到的子树更优即可。

关于匹配的Code(不匹配其子树)

qosrttree(1,k);  //dis数组排序(共有k棵子树需要匹配)
qsortarmy(1,o);  //time数组排序(共有o支军队)
zz:=1;
for i:=1 to k do
begin
    while (time[zz]<dis[i]) and (zz<=o) do inc(zz); 
    //while循环退出说明time[zz]>=dis[i],即第zz个军队可以匹配第i棵子树
    inc(zz);
    if zz>o then break;
end;
if zz<=o then 匹配成功
         else 匹配失败; 

关于匹配的Code(匹配其子树)

qosrttree(1,k);  //dis数组排序 hiy[i]表示第i棵子树的编号
qsortarmy(1,o);  //time数组排序 yl[i]表示第i支军队所属子树的编号
zz:=1;
for i:=1 to j do
begin
    if fz[hjy[i]] then continue; //如果此子树已被匹配则不需再浪费军队
    while ((time[zz]<dis[i]) or (fz[yl[zz]]=false)) and (zz<=k) do
    //如果第zz支军队不能匹配第i棵子树,那还不如匹配自己的所属子树
    //或者第zz支军队的所属子树(设其为第j棵子树)尚未被匹配(dis[j]一定大于等于dis[i]),
    //那还不如匹配第j棵子树
    begin
        fz[yl[zz]]:=true;
        if fz[hjy[i]] then break; //如果第i棵子树已被匹配则不需再浪费军队
        inc(zz);
    end;
    fz[hjy[i]]:=true;
    if zz>k then break;
    inc(zz);
end;
if zz>k then 匹配失败
        else 匹配成功;

你可能感兴趣的:(解题报告,二分,NOIP2012,疫情控制,树上倍增)