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;
}

 

posted @ 2023-11-01 21:01  CRt0729  阅读(10)  评论(0编辑  收藏  举报