洛谷1041 傳染病控制

NOIP2003 

原題地址

https://www.luogu.org/problem/show?pid=1041

搜索

題目描述 Description

【問題背景】

近來,一種新的傳染病肆虐全球。蓬萊國也發現了零星感染者,爲防止該病在蓬萊國大範圍流行,該國政府決定不惜一切代價控制傳染病的蔓延。不幸的是,由於人們尚未完全認識這種傳染病,難以準確判別病毒攜帶者,更沒有研製出疫苗以保護易感人羣。於是,蓬萊國的疾病控制中心決定採取切斷傳播途徑的方法控制疾病傳播。經過 WHO(世界衛生組織)以及全球各國科研部門的努力,這種新興傳染病的傳播途徑和控制方法已經研究清楚,剩下的任務就是由你協助蓬萊國疾控中心制定一個有效的控制辦法。

【問題描述】

研究表明,這種傳染病的傳播具有兩種很特殊的性質;第一是它的傳播途徑是樹型的,一個人X只可能被某個特定的人Y感染,只要Y不得病,或者是XY之間的傳播途徑被切斷,則X就不會得病。第二是,這種疾病的傳播有周期性,在一個疾病傳播週期之內,傳染病將只會感染一代患者,而不會再傳播給下一代。這些性質大大減輕了蓬萊國疾病防控的壓力,並且他們已經得到了國內部分易感人羣的潛在傳播途徑圖(一棵樹)。但是,麻煩還沒有結束。由於蓬萊國疾控中心人手不夠,同時也缺乏強大的技術,以致他們在一個疾病傳播週期內,只能設法切斷一條傳播途徑,而沒有被控制的傳播途徑就會引起更多的易感人羣被感染(也就是與當前已經被感染的人有傳播途徑相連,且連接途徑沒有被切斷的人羣)。當不可能有健康人被感染時,疾病就中止傳播。所以,蓬萊國疾控中心要制定出一個切斷傳播途徑的順序,以使盡量少的人被感染。你的程序要針對給定的樹,找出合適的切斷順序。

輸入描述 Input Description

輸入格式的第一行是兩個整數n(1≤n≤300)和p。接下來p行,每一行有兩個整數i和j,表示節點i和j間有邊相連(意即,第i人和第j人之間有傳播途徑相連)。其中節點1是已經被感染的患者。

輸出描述 Output Description

只有一行,輸出總共被感染的人數。

樣例輸入 Sample Input

7 6

1 2

1 3

2 4

2 5

3 6

3 7

樣例輸出 Sample Output

3

數據範圍及提示 Data Size& Hint

n<=300

 

解題思路

乍一看好像是樹P加貪心,然而事實上樹P還差不多,貪心就扯遠了。仔細想一想這題壓根不符合貪心的性質,有人舉反例說菊花形的就顯然不符合。所以,排除了貪心,再看看這良心的數據範圍,跑一跑DFS就可以了。

1. 首先建樹(雙向邊),然後跑出每個點子樹的size(包含本身),同時確定父子關係,開一個vector存每一層(同一深度)的點的編號。

2. 以深度deep和當前可感染人數cnt爲關鍵詞進行DFS:枚舉深度爲deep的所有點,如果滿足條件(沒有被阻斷),截斷父親節點連向該點的邊——將該點極其所有兒子節點打上標記(爲啥是兒子節點而不是子樹上的所有節點?我們知道dfs是一層一層來的,判斷是否能進行dfs的條件是由上一層的選擇情況決定的,所以只與上一層的操作有關,所以只給兒子節點打標記就好了),同時可感染人數cnt減去該點子樹規模size[i],進行下一層的搜索。注意這是一個回溯的過程,dfs之後要清空所打的標記。每一層DFS時要判斷當前cnt是否能更新答案。

3. 輸出答案,return 0。

參考代碼

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
int num=0,ans,n,m,v[350],size[350],fa[350];
bool vis[350];
vector<int>d[300];
struct mc
{
    int x,y,ne;
}e[10086];
 
void put(int x,int y)
{
    num++;
    e[num].x=x;
    e[num].y=y;
    e[num].ne=v[x];
    v[x]=num;
}
 
void make(int x,int deep)
{
    size[x]=1;
    if (v[x]==1&&x!=1)return;
    for (int i=v[x];i;i=e[i].ne)
    {
       int y=e[i].y;
       if (!vis[y])
       {
           fa[y]=x;
           d[deep+1].push_back(y);
           vis[y]=1;
           make(y,deep+1);
           size[x]+=size[y];
       }
    }
}
 
void clean(int x,int t)
{
    vis[x]=t;
    for (int i=v[x];i;i=e[i].ne)
    {
       int y=e[i].y;
       if (y!=fa[x])
       {
           vis[y]=t;
           clean(y,t);
       }
    }
}
 
void dfs(int deep,int cnt)
{
    ans=min(ans,cnt);
    for (inti=0;i<d[deep].size();i++)
    {
       int y=d[deep][i];
       if (!vis[y])
       {
           clean(y,1);
           dfs(deep+1,cnt-size[y]);
           clean(y,0);
       }
    }
}
 
int main()
{
    int x,y;
    cin>>n>>m;
    for (int i=1;i<=m;i++)
    {
       cin>>x>>y;
       put(x,y);
       put(y,x);
    }
    memset(vis,false,sizeof(vis));
    d[1].push_back(1);
    vis[1]=1;
    make(1,1);
    ans=n;
    memset(vis,false,sizeof(vis));
    vis[1]=1;
    dfs(2,n);
    cout<<ans;
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章