树上简单问题->巡逻(洛谷3629)

题意:
一颗树,从点1出发,初始代价是访问每个点1次回到点1。现在要加k <= 2条边,求加了边后的最小代价。

分析:
当k = 1时,代价就是初始代价-直径 + 1
当k = 2时,目前还不能理解

void solve(){
    int n, k;
    cin >> n >> k;

    vector<vector<int>> al(n + 1);
    for (int i = 1; i < n; ++i){
        int u, v;
        cin >> u >> v;
        al[u].emplace_back(v);
        al[v].emplace_back(u);
    }

    vector<int> dist(n + 1);

    function<void(int, int, int)> dfs = [&](int u, int p, int d){
        dist[u] = d;
        for (const auto& v : al[u]){
            if (v != p){
                dfs(v, u, d + 1);
            }
        }
    };

    int now = 1;
    dfs(now, 0, 0);

    now = max_element(dist.begin(), dist.end()) - dist.begin();
    dfs(now, 0, 0);

    int ans = 2 * (n - 1) - *max_element(dist.begin(), dist.end()) + 1;

    cout << ans << '\n';

}

24.5.21 更新
如何理解k == 2的情况呢?就是k=1的时候造的环会节省一些边只走一次,但是第二次建了环以后,为了让第二个环一定走一次,第一次节省的边可能会需要走两次,才能满足这个条件,所以只要把走两次的边,从贡献中删去即可。为了达到这种计算效果,把第一次节省的边都存下来(记录父亲节点和直径的一个端点),然后在第二次遍历的时候,如果当前的边已经在第一次被节省了,那么在第二次中这个直径不会再被节省了,就要把贡献删去!将权重设为-1完美匹配这种情况。

void solve(){
    int n, k;
    cin >> n >> k;

    vector<vector<int>> al(n + 1);
    for (int i = 1; i < n; ++i){
        int u, v;
        cin >> u >> v;
        al[u].push_back(v);
        al[v].push_back(u);
    }

    vector<int> dist(n + 1);
    vector<int> path(n + 1);
    function<void(int, int, int, bool)> dfs = [&](int u, int p, int d, bool cal_path = false){
        dist[u] = d;
        if (cal_path){
            path[u] = p;
        }
        for (const auto& v : al[u]){
            if (v != p){
                dfs(v, u, d + 1, cal_path);
            }
        }
    };

    dfs(1, 0, 0, false);
    int point_1 = max_element(dist.begin(), dist.end()) - dist.begin();
    dfs(point_1, 0, 0, true);
    int point_2 = max_element(dist.begin(), dist.end()) - dist.begin();

    int dist_d1 = dist[point_2];

    if (k == 1){
        cout << (n - 1) * 2 - (dist_d1) + 1 << '\n';
    }
    else{
        dist.clear();
        vector<bool> in_path(n + 1);
        for (int u = point_2; u; u = path[u]){
            in_path[u] = 1;
        }
        int dist_d2 = 0;
        vector<int> weight(n + 1, 1);
        vector<int> dp(n + 1);
        function<void(int, int)> dpCal = [&](int u, int p){
            for (const auto&v : al[u]){
                if (v != p){
                    if (in_path[u] && in_path[v]){
                        weight[v] = -1;
                    }
                    dpCal(v, u);
                    dist_d2 = max(dist_d2, dp[u] + dp[v] + weight[v]);
                    dp[u] = max(dp[u], dp[v] + weight[v]);
                }
            }
        };
        dpCal(1, 0);

        cout << (n - 1) * 2 - (dist_d1 + dist_d2) + 2 << '\n';
    }
}
posted @ 2024-01-12 11:00  _Yxc  阅读(4)  评论(0编辑  收藏  举报