[NOIP2003] 传染病控制题解

问题 F: [NOIP2003] 传染病控制

时间限制: 1 Sec  内存限制: 128 MB

题目描述

【问题背景】

近来,一种新的传染病肆虐全球。蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府 决定不惜一切代价控制传染病的蔓延。不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带者,更没有研制出疫苗以保护易感人群。于是,蓬莱国 的疾病控制中心决定采取切断传播途径的方法控制疾病传播。经过 WHO (世界卫生组织)以及全球各国科研部门的努力,这种新兴传染病的传播途径和控制方法已经研究消除,剩下的任务就是由你协助蓬莱国疾控中心制定一个有效的控 制办法。

【问题描述】

研究表明,这种传染病的传播具有两种很特殊的性质;第一是它的 传播途径是树型的,一个人 X 只可能被某个特定的人 Y 感染,只要 Y 不得病,或者是 XY 之间的传播途径被切断,则 X 就不会得病。第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。

这 些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手 不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与 当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传 播途径的顺序,以使尽量少的人被感染。

你的程序要针对给定的树,找出合适的切断顺序。

输入

输入格式的第一行是两个整数 n ( 1≤n≤300 )和 p 。接下来 p 行,每一行有两个整数 i 和 j ,表示节点 i 和 j 间有边相连(意即,第 i 人和第 j 人之间有传播途径相连)。其中节点1 是已经被感染的患者。

输出

只有一行,输出总共被感染的人数。

样例输入

7 6
1 2
1 3
2 4
2 5
3 6
3 7

样例输出

3

  这道题总体来看还是算比较容易的一类爆搜题,可以打贪心去优化,但只有贪心是不对的,虽然貌似只WA一个点,但也只是数据水,尽管董学长的“估价函数”可以卡过,但也只是针对这一个数据,很容易举出反例,因此不多赘述。
  这道题基本一个深搜就可以搞定,我是先维护一个队列,表示在下一个周期中可能会被感染的点,然后将队列复制,挨个去枚举其中因被控制而没被感染的点,然后挨个深搜,时间虽然比贪心慢了不少,但其实也是无伤大雅的,至少只要是合法数据就一定卡不到它。
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<map>
  7 #include<queue>
  8 #include<string>
  9 #include<cmath>
 10 using namespace std;
 11 int n,p,zz;
 12 struct ro{
 13     int to;
 14     int next;
 15     int from;
 16     int bh,size;
 17 }road[900];
 18 int a[350];
 19 void build(int x,int y){
 20     zz++;
 21     road[zz].bh=zz;
 22     road[zz].to=y;
 23     road[zz].from=x;
 24     road[zz].next=a[x];
 25     a[x]=zz;
 26 }
 27 int fa[350],son[350],ans=0x7fffffff;
 28 void dfs1(int x){
 29     for(int i=a[x];i>0;i=road[i].next)
 30     {
 31         int y=road[i].to;
 32         if(y!=fa[x])
 33         {
 34             son[x]++;
 35             fa[y]=x;
 36             dfs1(y);
 37             road[i].size=son[y];
 38         }
 39     }
 40 }
 41 int q[9000],head,en;
 42 void bfs(int js){
 43     if(js>=ans) return;
 44     int qq[9000],hea=head,ed=en;
 45     memcpy(qq,q,sizeof(q));
 46     int jj=js;
 47     for(int i=hea;i<=ed;i++)
 48     {
 49         js=jj;
 50         head=1,en=0;
 51         memset(q,0,sizeof(q));
 52         for(int j=hea;j<=ed;j++)
 53         {
 54             if(i==j) continue;
 55             js++;
 56             for(int k=a[qq[j]];k>0;k=road[k].next)
 57             {
 58                 int y=road[k].to;
 59                 if(y!=fa[qq[j]])
 60                 {
 61                     en++;
 62                     q[en]=y;
 63                 }
 64             }
 65         }
 66         if(js>ans)
 67             return;
 68         if(en==0)
 69         {
 70             ans=min(ans,js);
 71             return;
 72         }
 73         if(js!=jj) bfs(js);
 74     }
 75     
 76 }
 77 int main(){
 78     freopen("epidemic.in","r",stdin);
 79     freopen("epidemic.out","w",stdout);
 80     scanf("%d%d",&n,&p);
 81     for(int i=1;i<=p;i++)
 82     {
 83         int x,y;
 84         scanf("%d%d",&x,&y);
 85         build(x,y);
 86         build(y,x);
 87     }
 88     dfs1(1);
 89     head=1;
 90     cout<<endl;
 91     for(int i=a[1];i>0;i=road[i].next)
 92     {
 93         int y=road[i].to;
 94         en++;
 95         q[en]=y;
 96     }
 97     bfs(1);
 98     printf("%d
",ans);
 99     //while(1);
100     return 0;
101 }
View Code
 
原文地址:https://www.cnblogs.com/liutianrui/p/7323233.html