zoukankan      html  css  js  c++  java
  • NC24953 树形dp(最小支配集)

    细节

    题意

      给你一棵无向树,问你最少用多少个点可以覆盖掉所有其他的点。 • (一个点被盖,它自己和与它相邻的点都算被覆盖)

    思路

      状态: 选他,选他儿子,选他父亲都对子树答案有影响。

    设:

    dp[i][0]:选点i,并且以点i为根的子树都被覆盖了。 

    dp[i][1]:不选点i,i被其儿子覆盖

    dp[i][2]:不选点i,被其父亲覆盖(儿子可选可不选) 

      状态转移方程: ( u为儿子,i为当前点)

     dp[i][0]=1+Σmin(dp[u][0],dp[u][1],dp[u][2]) 

    dp[i][2]=Σ(dp[u][1],dp[u][0]) 

    对于dp[i][1]的讨论稍微复杂一点——他的所有儿子里面必须有一个取dp[u][1],且他的儿子不存在dp[u][2]。

    也就是说对于所有i的儿子,若每一个儿子的都dp[u][1] < dp[u][0]。则只需要让结果dp[i][1]加上min(dp[y][0]-dp[y][1])即可。

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <map>
    #include <iomanip>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <set>
    #include <vector> 
    // #include <bits/stdc++.h>
    #define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #define sp ' '
    #define endl '
    '
    #define FOR(i,a,b) for( int i = a;i <= b;++i)
    #define bug cout<<"--------------"<<endl
    #define P pair<int, int>
    #define fi first
    #define se second
    #define pb(x) push_back(x)
    #define ppb() pop_back()
    #define mp(a,b) make_pair(a,b)
    #define ms(v,x) memset(v,x,sizeof(v))
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define repd(i,a,b) for(int i=a;i>=b;i--)
    #define sca3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define sca2(a,b) scanf("%d %d",&(a),&(b))
    #define sca(a) scanf("%d",&(a));
    #define sca3ll(a,b,c) scanf("%lld %lld %lld",&(a),&(b),&(c))
    #define sca2ll(a,b) scanf("%lld %lld",&(a),&(b))
    #define scall(a) scanf("%lld",&(a));
    
    
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    ll powmod(ll a, ll b, ll mod){ll sum = 1;while (b) {if (b & 1) {sum = (sum * a) % mod;b--;}b /= 2;a = a * a % mod;}return sum;}
    
    const double Pi = acos(-1.0);
    const double epsilon = Pi/180.0;
    const int maxn = 2e5+100;
    std::vector<int> e[maxn];
    int n;
    //0:选择。1:不选择,被儿子覆盖。2:不选择,没被儿子覆盖(准备被父亲覆盖)
    int dp[maxn][5];
    int h[maxn];
    int ans1 = 0,ans2 = 0;
    void dfs(int x,int fa)
    {
        dp[x][0] = 1,dp[x][1] = dp[x][2] = 0;
        int cha = 999999,flag = 0;
        for(auto y : e[x]){
            if(y == fa) continue;
            dfs(y,x);
            dp[x][2] += min(dp[y][1],dp[y][0]);
            dp[x][0] += min(min(dp[y][0],dp[y][1]),dp[y][2]);
            //儿子一定要有一个放的,但是不必要是所有都是放的。
            dp[x][1] += min(dp[y][0],dp[y][1]);
            if(dp[y][1] < dp[y][0]){
               cha = min(cha,dp[y][0]-dp[y][1]); 
            } else flag = 1;
        }
        if(flag == 0) dp[x][1] += cha;
    }
    int main()
    {
        //freopen("input.txt", "r", stdin);
        while(scanf("%d",&n) != EOF){
            rep(i,1,n){
                e[i].clear();
            }
            ans1 = 1e6,ans2 = 1e6;
            rep(i,1,n){
                dp[i][1] = 1e5;
                dp[i][0] = 1e5;
            }
            rep(i,1,n-1){
                int x,y;
                sca2(x,y);
                e[x].pb(y);
                e[y].pb(x);
            }
    
            dfs(1,0);
            printf("%d
    ",min(dp[1][1],dp[1][0]));
        }
    
    
    }
  • 相关阅读:
    Java实现 LeetCode 461 汉明距离
    在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)
    AM335x(TQ335x)学习笔记——挂载Ramdisk
    Ramdisk文件系统的制作与调试运行
    u-boot向linux内核传递启动参数(详细)
    uboot环境变量与内核MTD分区关系
    MMU
    INTERRUPT CONTROLLER
    UART
    GPIO
  • 原文地址:https://www.cnblogs.com/jrfr/p/13509295.html
Copyright © 2011-2022 走看看