1. 程式人生 > >Luogu1041 NOIP2003T4 傳染病控制 搜索

Luogu1041 NOIP2003T4 傳染病控制 搜索

tar tle ont create getch 需要 lan col tor

題目傳送門:https://www.luogu.org/problemnew/show/P1041

題意:一棵有$N$個節點的有根樹的根節點($1$號點)出現了傳染病病毒,每一次你可以切斷樹上的一條邊,然後病毒就會沿著邊向葉子節點拓展一層,感染新一層節點,求最少有多少個節點被感染(1號節點最開始被感染)。$N \leq 300$


$15$年前的搜索題就是不一樣,暴搜加個最優化剪枝就能過$qwq$

根據貪心可以知道,每一次切斷的一條邊必定聯系最新被感染的節點和它的兒子,所以每一次只需要枚舉下面的哪個兒子不會被感染就可以了,復雜度$O($玄學$)$

 1 #include<bits/stdc++.h>
 2
using namespace std; 3 inline int read(){ 4 int a = 0; 5 char c = getchar(); 6 while(!isdigit(c)) c = getchar(); 7 while(isdigit(c)) a = (a << 3) + (a << 1) + (c ^ 48) , c = getchar(); 8 return a; 9 } 10 inline int min(int a , int b){ 11 return a < b ? a : b;
12 } 13 vector < int > Ed[301]; 14 queue < int > q; 15 int minN = 0x3f3f3f3f; 16 bool vis[301]; 17 void choose(int , queue < int >); 18 void create(int num , queue < int > q){ 19 queue < int > q1; 20 register int sum = 0; 21 while(!q.empty()){ 22 int t = q.front();
23 q.pop(); 24 num++; 25 for(register int i = 0 ; i < Ed[t].size() ; i++) 26 if(!vis[Ed[t][i]]){ 27 q1.push(Ed[t][i]); 28 if(num + ++sum > minN) return; 29 } 30 } 31 if(num + sum > minN) return; 32 if(sum == 0){ 33 minN = min(minN , num); 34 return; 35 } 36 choose(num , q1); 37 } 38 int main(){ 39 register int n = read() , p = read(); 40 for(register int i = 0 ; i - p ; i++){ 41 int a = read() , b = read(); 42 Ed[a].push_back(b); 43 Ed[b].push_back(a); 44 } 45 q.push(1); 46 vis[1] = 1; 47 create(0 , q); 48 printf("%d" , minN); 49 return 0; 50 } 51 void choose(int num , queue < int > q){ 52 register int first = q.front(); 53 do{ 54 vis[q.front()] = 1; 55 q.push(q.front()); 56 q.pop(); 57 }while(q.front() - first); 58 do{ 59 register int t = q.front(); 60 q.pop(); 61 create(num , q); 62 q.push(t); 63 }while(q.front() - first); 64 while(!q.empty()){ 65 vis[q.front()] = 0; 66 q.pop(); 67 } 68 }

Luogu1041 NOIP2003T4 傳染病控制 搜索