题目链接:https://www.luogu.org/problemnew/show/P1041
思路:
让感染的人数最少,即让不被感染的人数最大。
那么有一个贪心策略即为先搜索子树大小大的,搭配一个最优性剪枝使用更佳。
朴素做法就是按深度由小到大去枚举断边后的情况,在这其中即可统计最大值。
记得回溯。
代码:
#include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <vector> #include <algorithm> const int INF=1<<30; const int MAXN=10050; using namespace std; vector<int> g[MAXN],w[MAXN]; int n,p,u,v,cnt,num,dep[MAXN],sonnum[MAXN]; bool tag[MAXN]; void update(int x,bool s){ tag[x]=s; for(int i=0;i<(int)g[x].size();i++){ tag[g[x][i]]=s; update(g[x][i],s); } } void dfs1(int x){ sonnum[x]=1; for(int i=0;i<(int)g[x].size();i++){ int to=g[x][i]; dep[to]=dep[x]+1; dfs1(to); sonnum[x]+=sonnum[to]; } } void dfs2(int x){ if((int)w[x].size()==0) return ; for(int i=0;i<(int)w[x].size();i++){ int to=w[x][i]; if(tag[to]) continue; cnt+=sonnum[to]; num=max(num,cnt); update(to,true); dfs2(x+1); update(to,false); cnt-=sonnum[to]; } } int main(){ ios::sync_with_stdio(false); cin>>n>>p; for(int i=1;i<=p;i++){ cin>>u>>v; if(u>v) swap(u,v);//由于并没有建双向边,那就得按照一个顺序来建树 g[u].push_back(v); } dfs1(1); for(int i=1;i<=n;i++) w[dep[i]].push_back(i); dfs2(1); printf("%d ",n-num); return 0; }