Gym - 102460B The Power Monitor System

题意:

给定一棵有 n n 个结点的树,开始时树的结点和边均为白色,现要求将结点和边全部染黑,可以选择一个结点,将其直接染黑,代价为 1 1 ,结果为该结点及其邻接结点、边均被染黑。对于其他结点递归地考虑:① 若某条边被染黑,则两端结点被染黑;② 若某条边两端结点被染黑,则该边被染黑;③ 若某个点度为 k > 1 k \gt 1 ,且其中 k 1 k - 1 条边被染黑,则剩余的那条边也被染黑。求最小代价将树的结点和边均染黑。 ( n 1 0 5 ) (n \leq 10^5)

链接:

https://vjudge.net/problem/Gym-102460B

解题思路:

贪心,然后发现还是要树形 dp。树形 d p dp d p [ u ] [ 0 / 1 / 2 ] [ 0 / 1 ] dp[u][0/1/2][0/1] ,其中 0 / 1 / 2 0/1/2 表示三种被染黑的点: 0 0 表示为下方的黑点传递而被染黑, 1 1 表示被直接染黑, 2 2 表示为上方的黑点传递而被染黑。 0 / 1 0/1 表示子树内是否缺一条边被染黑。
 
转移:
d p [ u ] [ 1 ] [ 0 ] dp[u][1][0] 最好考虑,直接为 d p [ v ] [ 0 / 1 / 2 ] [ 0 / 1 ] + 1 \sum{dp[v][0/1/2][0/1]} + 1
d p [ u ] [ 2 ] [ 0 ] = d p [ v ] [ 0 ] [ 1 ] dp[u][2][0] = \sum{dp[v][0][1]} ,不能由 d p [ v ] [ 0 ] [ 0 ] dp[v][0][0] 转移( 00 00 状态下父边会被染黑)
d p [ u ] [ 2 ] [ 1 ] = d p [ u ] [ 2 ] [ 0 ] dp[u][2][1] = dp[u][2][0] 状态下,其中一棵子树状态替换为 20 / 21 20/21 ,取最优
d p [ u ] [ 0 ] [ 0 ] = dp[u][0][0] = 至少一棵子树状态为 00 / 10 00/10 (状态含义,被下方传递染黑)+ 其他子树取 m i n { 00 , 01 , 10 } min\{00, 01, 10\}
d p [ u ] [ 0 ] [ 1 ] = d p [ u ] [ 0 ] [ 0 ] dp[u][0][1] = dp[u][0][0] 状态下,其中的“其他子树“中的一棵子树状态替换为 20 / 21 20/21

参考代码:

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int inf = maxn;
const int mod = 1e9 + 7;
 
vector<int> G[maxn];
int deg[maxn];
ll dp[maxn][3][2];
int n;
 
void dfs(int u, int f){
 
    for(int i = 0; i < 3; ++i){
 
        for(int j = 0; j < 2; ++j){
 
            dp[u][i][j] = inf;
        }
    }
    dp[u][1][0] = 1, dp[u][2][0] = 0;
    if(deg[u] == 1 && f) return;
    dp[u][0][0] = dp[u][0][1] = dp[u][2][0] = dp[u][2][1] = 0;
    ll tp0[2] = {0, inf}, tp1[2][2] = {0, inf, inf, inf};
    for(auto &v : G[u]){
 
        if(v == f) continue;
        dfs(v, u);
        ll tmp = min(dp[v][1][0], min(dp[v][0][0], dp[v][0][1]));
        tp0[1] = min(tp0[1] + tmp, tp0[0] + min(dp[v][0][0], dp[v][1][0])), tp0[0] += tmp;
        tp1[1][1] = min(tp1[1][1] + tmp, min(tp1[0][1] + min(dp[v][2][0], dp[v][2][1]), tp1[1][0] + min(dp[v][0][0], dp[v][1][0])));
        tp1[0][1] = min(tp1[0][1] + tmp, tp1[0][0] + min(dp[v][0][0], dp[v][1][0]));
        tp1[1][0] = min(tp1[1][0] + tmp, tp1[0][0] + min(dp[v][2][0], dp[v][2][1]));
        tp1[0][0] += tmp;
        dp[u][1][0] += min(min(dp[v][0][0], dp[v][0][1]), min(dp[v][1][0], min(dp[v][2][0], dp[v][2][1])));
        dp[u][2][1] = min(dp[u][2][0] + min(dp[v][2][0], dp[v][2][1]), dp[u][2][1] + dp[v][0][1]);
        dp[u][2][0] += dp[v][0][1];
    }
    dp[u][0][0] = tp0[1], dp[u][0][1] = tp1[1][1];
}
 
int main(){
 
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n;
    for(int i = 1; i < n; ++i){
 
        int u, v; cin >> u >> v;
        G[u].pb(v), G[v].pb(u);
        ++deg[u], ++deg[v];
    }
    dfs(1, 0);
    cout << min(dp[1][1][0], min(dp[1][0][0], dp[1][0][1])) << endl;
    return 0;
}

 
专门练了很多树形 d p dp 的题目,就是为了搞定这道。尽管还是花了整整一天,也值了,哈哈。

发布了58 篇原创文章 · 获赞 0 · 访问量 4824

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/104110986
今日推荐