NOIP2003 传染病控制 深搜/剪枝
思路
题目大意是:把一棵树按深度分层,每一层断掉一条边,是剩下的节点数最小。
其实,我们可以将问题转换为断掉的节点数最多。
首先,贪心不可行,很容易被卡。
因为数据只有300,直接搜索就行。
搜索时一层一层搜,枚举断掉哪条边,并标记后代。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e3+10,inf = 0x3f3f3f3f; int f[N],n,p,s,ans; vector<int> d[N],a[N]; void init(int u,int dep) { d[dep].push_back(u);//第dep深度有u for(int i = 0; i < a[u].size(); i++) init(a[u][i],dep + 1); } int work(int u,int t) //t = 1就代表这个结点u被用过了 { int ss = 1; f[u] = t; for(int i = 0; i < a[u].size(); i++) ss += work(a[u][i],t); //继续断开和u连接的i结点或者拼接回来 return ss; } void dfs(int dep) { for(int i = 0; i < d[dep].size(); i++) { if(f[d[dep][i]])continue; s += work(d[dep][i],1); //把深度为dep的第i个结点的所有结点全部断开 ans = max(ans,s); //获取当前最大断开结点数 dfs(dep + 1); //因为每一轮只能断掉一条传染链,所以接下来会传染深度+1 s -= work(d[dep][i],0); //把断开过的结点都接回来 } } int main() { cin >> n >> p; for(int i = 1; i <= p; i++) { int x,y; cin >> x >> y; if(x > y) swap(x,y); a[x].push_back(y); } init(1,1); //建树,按层数深度把相邻结点都连接到d数组上 dfs(2); //第一层是感染源,所以要从第二层开始 printf("%d",n - ans); //原有结点 - 最大断开结点数就是被感染人数 return 0; }