P1041 传染病控制[搜索][树]

P1041 传染病控制

远古NOIP题放到现在真的容易得一批

给你一棵树,以1为根。1点有病,并且有边就会传染,一轮传染可以断边一次,求最好的断边方案下的最小感染人数。

有一个贪心的思想:当前哪一层要被感染,我们就亡羊补牢,去断这个路径上的任意一条边。

因为树是越走size越小的,去断上面已经感染的就很睿智,去断下面的最终感染的人数会更多,保护的人变少了。

很自然可以预处理出这棵树每个点的深度,然后开个桶存每个深度下的所有点。

之后就是爆搜了:

如果上一层被感染了,那么就有这么一次权利去阻止感染,可以进入下一层状态。

注意爆搜的终止条件,搜到最大深度+1是一个方面:如果这一深度的人都不会被感染,就可以结算答案了。

剪枝:因为是求最小值,所以直接无脑最优性剪枝即可。


我的错误:在下一层状态的更改用了两个循环!其实只需要两个循环一前一后即可。

代码:

/*************************************************************************
 @Author: Garen
 @Created Time : Wed 13 Feb 2019 04:26:31 PM CST
 @File Name: P1041.cpp
 @Description:
 ************************************************************************/
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long
const int maxn = 305;
const int INF = 0x3f3f3f3f;
std::vector<int> G[maxn];
std::vector<int> help[maxn];
int dep[maxn], fa[maxn];
bool infected[maxn];
bool changed[maxn];
int n, m;
int lim;
int ans = INF;
void dfs1(int u, int f) {
    dep[u] = dep[f] + 1; fa[u] = f;
    for(auto v : G[u]) {
        if(v == f) continue;
        dfs1(v, u);
    }
}
void dfs(int t, int res) {
    if(res >= ans) return;
    if(t == lim + 1) {
        ans = std::min(ans, res);
        return;
    }
    int cnt = 0;
    for(auto u : help[t]) {
        if(infected[fa[u]]) {
            infected[u] = true;
            changed[u] = true;
            cnt++;
        }
    }
    if(cnt == 0) {
        ans = std::min(ans, res);
        return;
    }
    for(auto u: help[t]) {
        if(changed[u]) {
            infected[u] = false;
            dfs(t + 1, res + cnt - 1);
            infected[u] = true;
        }
    }
    for(auto u : help[t]) {
        if(changed[u]) {
            infected[u] = changed[u] = false;
        }
    }
}
int main() {
    cin >> n >> m;
    while(m--) {
        int u, v; cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(1, 0);
    for(int i = 1; i <= n; i++) {
        lim = std::max(lim, dep[i]);
        help[dep[i]].push_back(i);
    }
    infected[1] = true;
    dfs(2, 1);
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/10381470.html
今日推荐