1 条题解

  • 0
    @ 2023-4-25 19:59:22
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <vector>
    using namespace std;
    /*
    dp[i][0] 表示i结点为根的子树被覆盖并且 i结点上有塔
      
    dp[i][1] 表示i结点为根的子树被覆盖并且i结点上没有塔
      
    dp[i][2]表示i结点为根的子树除了i全被覆盖了
    */
       
    int n , dp[10007][3] ;
    vector <int> G[10007] ;
      
    void dfs(int x , int fa )
    {
        dp[x][0] = 1 ;
        dp[x][1] = 7777777;
        int sum = 0 ;
        int z = G[x].size() ;
        for(int i = 0 ; i < z ; ++ i ) {
            int s = G[x][i];
            if( s == fa )
                continue;
            dfs( s , x );
            dp[x][0] += min( dp[s][0] , min(dp[s][1] , dp[s][2] ) );//可以由这三种情况转移 
            sum += min( dp[s][0] , dp[s][1] );//进行在 x 节点下的节点全覆盖求和 
            dp[x][2] += dp[s][1];//要让 x 节点未被覆盖,必须由其子节点的dp[s][1]转移 
        }
        if( z == 1 && x!= 1 ) return ;
        for(int i = 0 ; i < z ; ++ i )
        {
            int s = G[x][i];
            if( s == fa )
                continue;
            dp[x][1] = min( dp[x][1] , dp[s][0] + sum - min( dp[s][0] , dp[s][1] ));//该情况由在其子节点建塔dp[s][0]加上其子节点全覆盖的和 减去 之前在该状态下的累加 
        }
    }
       
    int main()
    {
        scanf("%d", &n );
        for(int i = 1 ; i < n ; ++ i )
        {
            int a , b ;
            scanf("%d%d", &a , &b );
            G[a].push_back(b);
            G[b].push_back(a);
        }
        dfs( 1 , 0 );
        printf("%d", min(dp[1][0] , dp[1][1] )); 
        return 0;
    }
    
    • 1

    信息

    ID
    2422
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    35
    已通过
    11
    上传者