zoukankan      html  css  js  c++  java
  • Strategic game(树形DP入门)

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1054

    题目大意:一棵树,要放置哨兵,要求最少放置多少哨兵能监视到所有的结点

    题目分析

    放置哨兵无非两种情况,放或不放,我们可以用dp[i][1]来表示第i个结点放置哨兵,dp[i][0]来表示第i个结点不放置哨兵,我们可以从上往下,从左往右来遍历树,所以这就用到了树形DP的知识,我们很容易知道,如果父亲结点没放哨兵,那么子结点肯定要放置哨兵,如果父亲放置了哨兵,那么子结点可以考虑放或者不放。所以很容易写出状态转移方程dp[v][1] += min(dp[u][1],dp[u][0]),dp[v][0] += dp[u][1],由于子结点可能有多个,我们要依次从左到右遍历所以我们必须开一个brother来存放它前一个兄弟结点,然后只要DFS递归的来从上往下遍历就可以得解了


    和我的上一篇差不多:https://www.cnblogs.com/wsy107316/p/11319167.html

    AC代码:

     1 /* */
     2 # include <iostream>
     3 # include <stdio.h>
     4 # include <string.h>
     5 # include <cstdlib>
     6 # include <cmath>
     7 # include <climits>
     8 # include <ctime>
     9 # include <algorithm>
    10 # include <deque>
    11 # include <bitset>
    12 # include <cctype>
    13 # include <queue>
    14 # include <stack>
    15 # include <list>
    16 # include <set>
    17 # include <map>
    18 # include <vector>
    19 using namespace std;
    20 const int maxn = 2000;
    21 bool vis[maxn];
    22 int dp[maxn][2];
    23 int n;
    24 vector<int>son[maxn];
    25 
    26 void dfs(int root)
    27 {
    28     vis[root]=1;
    29     for(int i=0; i<son[root].size(); i++ )
    30     {
    31         int v=son[root][i];
    32         if( !vis[v] )
    33         {
    34             dfs(v);
    35             dp[root][1] += min(dp[v][0], dp[v][1]);///0表示无哨兵,i处无哨兵则子结点处必须有哨兵
    36             dp[root][0] += dp[v][1];///1表示有哨兵,i处有哨兵的情况等于子结点处有哨兵或者无哨兵的最小值
    37         }
    38     }
    39 }
    40 
    41 int main()
    42 {
    43     int num, so, ss;
    44     while( ~ scanf("%d", &n) )
    45     {
    46         for(int i=0; i<=n; i++ )
    47             son[i].clear();
    48             memset(vis, 0, sizeof(vis));
    49 
    50             for(int i=0; i<n; i++ )
    51             {
    52                 dp[i][0] = 0;
    53                 dp[i][1] = 1;
    54             }
    55 
    56             for(int i=0; i<n; i++ )
    57             {
    58                 scanf("%d:(%d)", &num, &so);
    59                 for(int j=0; j<so; j++ )
    60                 {
    61                     scanf("%d", &ss);
    62                     son[num].push_back(ss);///num节点可以看到ss节点
    63                     son[ss].push_back(num);///则ss节点也可以看到num结点
    64                 }
    65             }
    66 
    67             dfs(0);///反正整棵树一定是联通的,那么就随便选一个作为根节点
    68             cout<<min(dp[0][0], dp[0][1])<<endl;
    69     }
    70     return 0;
    71 }
    View Code
  • 相关阅读:
    Lucas 定理
    C语言II博客作业04
    C语言II博客作业03
    C语言II博客作业02
    C语言II博客作业01
    学期总结
    First project
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
  • 原文地址:https://www.cnblogs.com/wsy107316/p/11319403.html
Copyright © 2011-2022 走看看