文章标题
2016-09-25 11:30
204 查看
【转】http://www.cnblogs.com/saltless/archive/2010/08/05/1793322.html
有人看到“二分答案”这个题目,可能会很不解。题目过程可以二分,答案怎么也能二分呢?
先看一个例题。
【描述】
现在某组织中(记作R)有n个人,他们的联络网形成一棵以Saltless为根的树,有边相连代表两人可以直接联络。
每个人有一个代号,Saltless代号为1,且除Saltless外每个人的父节点的代号小于他自己的代号。
由于某些原因,Saltless给R的成员分别下达紧急任务,R需要分成m组行动,每个组必须满足如下条件:
1、每个组员仅分在本组中
2、至少有一个组员
3、任意两个组员无需通过本组外的人就可以联络(但可以通过本组组员进行联络)
每个人有一个能力指数,一个组的能力指数是全组人能力指数之和。
对于任意一种正确的分组,平均度就是m组中最小能力指数。为了分组较为平均,Saltless希望平均度尽可能大。
【格式】
PROGRAM NAME: organ
INPUT FORMAT:
第一行为三个数:n,m,和Saltless的能力指数(1<=m<=n<=10000)。
接下来n-1行,每行两个数:此人的父节点代号和他的能力指数(能力指数值为正整数,不超过30,行数就是他本身的代号)
OUTPUT FORMAT:
输出格式: 一个数,表示最大的平均度。
SAMPLE INPUT (organ.in)
7 2 2
1 4
1 5
2 1
2 2
3 4
4 3
SAMPLE OUTPUT (organ.out)
10
【Hint】
分组:{1,3,6},{2,4,5,7}
看到这个题,出口很明显,可能首先想到DFS。但是10000的数据DFS显然是不能承受的。这时候我们采用二分答案。
我们先记录下所有人能力指数之和tot,然后假设它的中间值mid就是我们要找的最优解。然后根据这个下限进行分组,把得到的组数num和m进行比较,如果num>m则表示分组过多,则答案在mid+1到tot的区间内;如果num
有人看到“二分答案”这个题目,可能会很不解。题目过程可以二分,答案怎么也能二分呢?
事实上,当你看到找极大值中的最小值或者求极小值中的最大值的题目时,二分答案或许是一个不错的选择。根据数据范围判断是否选用二分(二分能把时间复杂度降到log n),再和上文所说的条件结合,一般就不会错了。
先看一个例题。
【描述】
现在某组织中(记作R)有n个人,他们的联络网形成一棵以Saltless为根的树,有边相连代表两人可以直接联络。
每个人有一个代号,Saltless代号为1,且除Saltless外每个人的父节点的代号小于他自己的代号。
由于某些原因,Saltless给R的成员分别下达紧急任务,R需要分成m组行动,每个组必须满足如下条件:
1、每个组员仅分在本组中
2、至少有一个组员
3、任意两个组员无需通过本组外的人就可以联络(但可以通过本组组员进行联络)
每个人有一个能力指数,一个组的能力指数是全组人能力指数之和。
对于任意一种正确的分组,平均度就是m组中最小能力指数。为了分组较为平均,Saltless希望平均度尽可能大。
【格式】
PROGRAM NAME: organ
INPUT FORMAT:
第一行为三个数:n,m,和Saltless的能力指数(1<=m<=n<=10000)。
接下来n-1行,每行两个数:此人的父节点代号和他的能力指数(能力指数值为正整数,不超过30,行数就是他本身的代号)
OUTPUT FORMAT:
输出格式: 一个数,表示最大的平均度。
SAMPLE INPUT (organ.in)
7 2 2
1 4
1 5
2 1
2 2
3 4
4 3
SAMPLE OUTPUT (organ.out)
10
【Hint】
分组:{1,3,6},{2,4,5,7}
看到这个题,出口很明显,可能首先想到DFS。但是10000的数据DFS显然是不能承受的。这时候我们采用二分答案。
我们先记录下所有人能力指数之和tot,然后假设它的中间值mid就是我们要找的最优解。然后根据这个下限进行分组,把得到的组数num和m进行比较,如果num>m则表示分组过多,则答案在mid+1到tot的区间内;如果num
program sai; var m,n,tot:longint; mid,num,l,r:longint; i:integer; p,w,t:array[0..10000]of longint; function get(x:longint):longint; //分组 var i,num:integer; begin num:=0; t:=w; for i:=n downto 1 do //从儿子找起,以消除后效性 if t[i]<x then t[p[i]]:=t[p[i]]+t[i] else inc(num);//如果一个组的能力指数之和达到了中间值就加一组 exit(num); end; begin assign(input,'sai.in'); reset(input); assign(output,'sai.out'); rewrite(output); readln(n,m,tot); w[1]:=tot; for i:=2 to n do begin readln(p[i],w[i]); tot:=tot+w[i]; end; l:=1; r:=tot; while l<=r do begin mid:=(l+r)>>1; //mid记录了临时的最优解 num:=get(mid); if num>=m then l:=mid+1 else r:=mid-1; //与组数进行比较,确定下一个搜索区间 end; writeln(r); //右指针记录的是最优解 close(input); close(output); end.