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 @   CRt0729  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示