1、传染病控制解题报告题意简述:给定一棵树,其根节点 1 是已经被感染的患者。在一个疾病传播周期内,只能切断树的一条边,然后所有被感染的节点的孩子节点也会被感染。要求一个最佳的切断边的方案,使被感染的节点数最小。解法分析:将被感染节点中深度最大的节点集合称之为最新传染源,设为 。当经过 个疾病传SX播周期,传染病传播的最新传染源的深度是一定的,即为 (根节点 1 的深度为 0) 。因X此可以得到以下动态规划算法:设 表示经过 X 个疾病传播周期且最新传染源集合),(Sf为 被感染节点的最小值,那么由 可以推得 ,其中S )(,(vSsonf表示 集合中所有的孩子节点, 是被切断边的一个深度较大的节
2、点。似乎问题已)(sonv经得到了很好的解决,但是考察一下算法的空间复杂度,达到了 ,这是完全不)2(NO可能实现的。鉴于空间上的问题,我们只好放弃动态规划。尝试先从简单的角度思考问题:搜索的效果会怎么样呢?分析一下问题的状态空间:题目给定的是一棵树。把题目中的树称为原树,搜索树的层数就是原树的深度,而搜索树的分叉数多少与原树的宽度有关。综合起来看,原树深度较大,宽度会较小;而原树宽度较大,深度又会较小,所以搜索树的规模没有想象中那么大。证明了搜索是“可能” 出解的,剩下的就是怎么搜的问题:在 个传播周期内疾病传播X达到的深度是一定的,为 。如果在深度小于 的位置切断边,由于已经通过它进行了X
3、X传播,切断是没有意义的;如果在深度大于 的位置切断边,效果肯定不如把它的祖先切断。因此最优的切断方法必须是切断与 相连的边中的一条。这样搜索已经可以通过大部S分数据,但是对于极限大数据还是无法出解,需要优化。优化一:初看这道题目的时候会想到贪心。也就是每次选节点数目最大的子树删除,虽然很容易找到反例,但是我们仍然可以认为选节点数目最大的子树删除更“可能”得到最优解,因此可以按照子树节点数目从大到小删除。优化二:最优性剪枝。设当前已经搜到了第 层,有 个节点已被感染,那么如果有XT即可剪枝。这是因为在一个疾病传播周期内,最多只能切断树的一bestSsonT1)(条边,所以在下一周期至少还有 个
4、新感染的节点。1)(SsonT优化三:搜索最后一两层时,由于子树的结构都相同,随便选择一个删除就可以退出了。加入这三个优化后,程序的效率大大提高。最大官方数据在 0.2s 内解出。参考程序:$R-,Q-,S-,I-$M 65521,0,655360Author:Zhou GelinDate:2005.1.11QQ:379688236MSN:Test ReportP4 1.7GWindows Xp SP1Turbo Pascal 7.0EPIDEMIC.in1 = 10.0 (0.06s)EPIDEMIC.in2 = 10.0 (0.08s)EPIDEMIC.in3 = 10.0 (0.05s)
5、EPIDEMIC.in4 = 10.0 (0.03s)EPIDEMIC.in5 = 10.0 (0.03s)EPIDEMIC.in6 = 10.0 (0.03s)EPIDEMIC.in7 = 10.0 (0.06s)EPIDEMIC.in8 = 10.0 (0.03s)EPIDEMIC.in9 = 10.0 (0.20s)EPIDEMIC.in0 = 10.0 (0.11s)program epidemic;const inputfilename=epidemic.in;outputfilename=epidemic.out;maxn=300;type pnode=node;node=reco
6、rddata:integer;next:pnode;end;list=array1maxnof integer;var n,p,maxdep,ans:integer;g:array1maxnof pnode;father:array1maxnof integer;dep:array1maxnof integer;sum:array1maxnof integer;deg:array1maxnof integer;son:array1maxnof list;a:array1maxnof boolean;procedure insert(a,b:integer);var q:pnode;beginn
7、ew(q);q.data:=b;q.next:=ga;ga:=q;end;procedure read_data;var i,a,b:integer;beginfillchar(deg,sizeof(deg),0);assign(input,inputfilename);reset(input);readln(n,p);for i:=1 to p dobeginreadln(a,b);insert(a,b);insert(b,a);dega:=dega+1;degb:=degb+1;end;close(input);end;procedure dfs(v:integer);var q:pnod
8、e;i,j,k:integer;beginif fatherv0 thenbegindegv:=degv-1;depv:=depfatherv+1;if depvmaxdep then maxdep:=depv;endelse depv:=1;getmem(sonv,2*degv);sumv:=1;q:=gv;i:=0;while qfatherv thenbegini:=i+1;sonvi:=q.data;fatherq.data:=v;dfs(q.data);sumv:=sumv+sumq.data;end;q:=q.next;end;for i:=1 to degv-1 dobegink
9、:=i;for j:=i+1 to degv doif sumsonvjsumsonvk then k:=j;j:=sonvi;sonvi:=sonvk;sonvk:=j;end;end;procedure search(deep,sick:integer);var i,j,tmp:integer;beginif deep=maxdep thenbeginif anssick then ans:=sick;exit;end;tmp:=0;for i:=1 to n doif ai and (depi=deep) thentmp:=tmp+degi;if tmp=0 then begin sea
10、rch(maxdep,sick); exit; end;if sick+tmp-1=ans then exit;for i:=1 to n doif ai and (depi=deep) thenfor j:=1 to degi doasonij:=true;for i:=1 to n doif ai and (depi=deep) thenfor j:=1 to degi dobeginasonij:=false;search(deep+1,sick+tmp-1);asonij:=true;if deep=maxdep-1 then break;end;for i:=1 to n doif
11、ai and (depi=deep) thenfor j:=1 to degi doasonij:=false;end;procedure answer;beginassign(output,outputfilename);rewrite(output);writeln(ans);close(output);end;var time:longint;begintime:=meml64:108;read_data;dfs(1);ans:=1000;fillchar(a,sizeof(a),0);a1:=true;search(1,1);time:=meml64:108-time;writeln(time);answer;end.