1. 程式人生 > >P1041 [2003NOIP提高組]傳染病控制

P1041 [2003NOIP提高組]傳染病控制

fine 針對 程序 highlight cst 以及 不惜 font 它的

P1041 傳染病控制

題目背景

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

題目描述

研究表明,這種傳染病的傳播具有兩種很特殊的性質;

第一是它的傳播途徑是樹型的,一個人X只可能被某個特定的人Y感染,只要Y不得病,或者是XY之間的傳播途徑被切斷,則X就不會得病。

第二是,這種疾病的傳播有周期性,在一個疾病傳播周期之內,傳染病將只會感染一代患者,而不會再傳播給下一代。

這些性質大大減輕了蓬萊國疾病防控的壓力,並且他們已經得到了國內部分易感人群的潛在傳播途徑圖(一棵樹)。但是,麻煩還沒有結束。由於蓬萊國疾控中心人手不夠,同時也缺乏強大的技術,以致他們在一個疾病傳播周期內,只能設法切斷一條傳播途徑,而沒有被控制的傳播途徑就會引起更多的易感人群被感染(也就是與當前已經被感染的人有傳播途徑相連,且連接途徑沒有被切斷的人群)。當不可能有健康人被感染時,疾病就中止傳播。所以,蓬萊國疾控中心要制定出一個切斷傳播途徑的順序,以使盡量少的人被感染。

你的程序要針對給定的樹,找出合適的切斷順序。

輸入輸出格式

輸入格式:

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

輸出格式:

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

輸入輸出樣例

輸入樣例#1:
7 6
1 2
1 3
2 4
2 5
3 6
3 7

  

輸出樣例#1:
3     
     

  


好神奇的一道題。

首先可以知道給定的是一棵樹,所以就是雙向邊,但是在這裏不需要建雙向邊。只需要讓兩個相連的節點保持一定的順序就行。

因為每一個周期只能剪短一條。所以我們可以用DFS來枚舉每一層周期剪短的是那條邊。

這裏我們需要用到每一層的節點和以每一個節點為根root的大小。

所以要講這些東西預處理。

然後進行DFS就可已得到答案了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>

#define boooooooooool bool
#define INF 2147483647

using namespace std;

int n, p, rootsize[303], cnt[303], ans = INF;

boooooooooool vis[303];
boooooooooool have_cut[303];

vector<int> FLOOR[303];
vector<int> tree[303];

int tree_size(int root, int now) {
	if(vis[root] == 1) return rootsize[root];
	vis[root] = 1;
	FLOOR[now].push_back(root);
	for(int i=0; i<tree[root].size(); i++)
		rootsize[root] += tree_size(tree[root][i], now+1);
	return rootsize[root];
}

void cut(int root) {
	have_cut[root] = true;
	for(int i=0; i<tree[root].size(); i++) cut(tree[root][i]);
}

void connect(int root) {
	have_cut[root] = false;
	for(int i=0; i<tree[root].size(); i++) connect(tree[root][i]);
}

void dfs(int floor, int now) {
	for(int i=0; i<FLOOR[floor+1].size(); i++) {
		if(have_cut[FLOOR[floor+1][i]]) continue;
		else {
			cut(FLOOR[floor+1][i]);
			dfs(floor+1, now-rootsize[FLOOR[floor+1][i]]);
			connect(FLOOR[floor+1][i]);
		}
	}
	ans = min(ans, now);
}

int main() {
	scanf("%d%d", &n, &p);
	for(int i=1; i<=n; i++) rootsize[i] = 1;
	for(int i=1; i<=p; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		if(x > y) swap(x, y);
		tree[x].push_back(y);
	}
	tree_size(1, 1);
	dfs(1, n);
	printf("%d", ans);
}

  

P1041 [2003NOIP提高組]傳染病控制