http://poj.org/problem?id=3659

题意: 给出一棵树(无向图),让你在上面选点放塔, 塔覆盖范围为当前点和相邻的点,用最小的塔覆盖所有点

解法1:树型DP
 dp[ i ][ 0 ], 表示该点不放塔, 且被祖先结点覆盖
 dp[ i ][ 1 ], 表示该点不放塔, 不被祖先覆盖
 dp[ i ][ 2 ], 放塔

 u为i 的子结点dp[ i ][ 0 ] = sum( min( dp[ u ][ 1 ], dp[ u ][ 2 ] ) );
 dp[ i ][ 2 ] = sum( min( dp[ u ][ 0 ], dp[ u ][ 2 ] ) ) + 1;
 dp[ i ][ 1 ] 如果其子节点中至少有一个点是放塔, 即存在 dp[ u ][ 2 ] <= dp[ u ][ 1 ]
 那么 dp[ i ][ 1 ] = sum( min( dp[ u ][ 1 ], dp[ u ][ 2 ] ) );
 否则 枚举其中一个子结点, 在该结点放塔( dp[ u ][ 2 ] ),其他仍保持dp[ u ][ 1 ]状态

 1 #include  < cstdio >
 2 #include  < complex >
 3 #include  < cstdlib >
 4 #include  < iostream >
 5 #include  < cstring >
 6 #include  < string >
 7 #include  < algorithm >
 8 #include  < cmath >
 9 #include  < ctime >
10 #include  < vector >
11 #include  < map >
12 #include  < queue >
13 using   namespace  std;
14
15 const   int  maxn  =   10004 ;
16 const   int  inf   =   10000000 ;
17
18 int  vis[ maxn ], id[ maxn ], f[ maxn ],  set [ maxn ];
19 int  head[ maxn ], e[ maxn  <<   1  ], next[ maxn  <<   1  ];
20 int  len;
21 int  dp[ maxn ][  3  ];
22
23 void  init( )
24 {
25    len = 0;
26    memset( head, 0sizeof( head ) );
27}

28
29 void  add(  int  u,  int  v )
30 {
31    next[ ++len ] = head[ u ];
32    head[ u ] = len;
33    e[ len ] = v;
34}

35
36 int  Min(  int  a,  int  b )  return ( a < b ? a : b ); }
37
38 void  DFS(  int  u )
39 {
40    vis[ u ] = 1;
41    if( head[ u ] == 0 )
42    {
43        dp[ u ][ 0 ] = 0;
44        dp[ u ][ 1 ] = inf;
45        dp[ u ][ 2 ] = 1;
46        return;
47    }

48    int sum[ 3 ] = 0 }, off = inf;
49    forint i = head[ u ]; i ; i = next[ i ] )
50    {
51        int v = e[ i ];
52        if!vis[ v ] )
53        {
54            DFS( v );
55            sum[ 0 ] += Min( dp[ v ][ 1 ], dp[ v ][ 2 ] );
56            sum[ 2 ] += Min( dp[ v ][ 0 ], dp[ v ][ 2 ] );
57            off = Min( off, dp[ v ][ 2 ] - dp[ v ][ 1 ] );
58            // 最后off <= 0 则存在 dp[ v ][ 2 ] <= dp[ v ][ 1 ]
59        }

60    }

61    dp[ u ][ 0 ] = sum[ 0 ];
62    dp[ u ][ 1 ] = sum[ 0 ];
63    dp[ u ][ 2 ] = sum[ 2 ] + 1;
64    if( off > 0 ) dp[ u ][ 1 ] = sum[ 0 ] + off;
65}

66
67 int  main( int  argc,  char   * argv[])
68 {
69    int u, v, n;
70    scanf( "%d"&n );
71    init( );
72    forint i = 1; i < n; i++ )
73    {
74        scanf( "%d%d"&u, &v );
75        add( u, v );
76        add( v, u );
77    }

78    DFS( 1 );
79    printf( "%d\n", Min( dp[ 1 ][ 1 ], dp[ 1 ][ 2 ] ) );
80    return 0;
81}

82



解法2:贪心

 先前序遍历一次对结点进行标志,然后从n到1进行O(n)贪心.
 每次选取还没覆盖的点,在该点的父亲结点放塔.

 1 #include  < cstdio >
 2 #include  < complex >
 3 #include  < cstdlib >
 4 #include  < iostream >
 5 #include  < cstring >
 6 #include  < string >
 7 #include  < algorithm >
 8 #include  < cmath >
 9 #include  < ctime >
10 #include  < vector >
11 #include  < map >
12 #include  < queue >
13 using   namespace  std;
14
15 const   int  maxn  =   10004 ;
16 int  vis[ maxn ], id[ maxn ], f[ maxn ],  set [ maxn ];
17 int  head[ maxn ], e[ maxn  <<   1  ], next[ maxn  <<   1  ];
18 int  len;
19
20 void  init( )
21 {
22    len = 0;
23    memset( head, 0sizeof( head ) );
24}

25
26 void  add(  int  u,  int  v )
27 {
28    next[ ++len ] = head[ u ];
29    head[ u ] = len;
30    e[ len ] = v;
31}

32
33 int  num;
34
35 void  DFS(  int  u )
36 {
37    vis[ u ] = 1;
38    id[ u ] = num++;
39    forint i = head[ u ]; i ; i = next[ i ] )
40    {
41        int v = e[ i ];
42        if!vis[ v ] )
43        {
44            DFS( v );
45            f[ id[ v ] ] = id[ u ];
46        }

47    }

48}

49
50 int  main( int  argc,  char   * argv[])
51 {
52    int u, v, n;
53    scanf( "%d"&n );
54    init( );
55    forint i = 1; i < n; i++ )
56    {
57        scanf( "%d%d"&u, &v );
58        add( u, v );
59        add( v, u );
60    }

61    num = 1;
62    memset( f, 0sizeof( f ) );
63    memset( vis, 0sizeof( vis ) );
64    DFS( 1 );
65    memset( set0sizeofset ) );
66    memset( vis, 0sizeof( vis ) );
67
68    int ans = 0;
69    forint i = n; i>= 1; i-- )
70    {
71        if!vis[ i ] )
72        {
73            if!set[ f[ i ] ] )
74            {
75                ans++;
76                set[ f[ i ] ] = 1;
77            }

78            vis[ i ] = 1;
79            vis[ f[ i ] ] = 1;
80            vis[ f[ f[ i ] ] ] = 1;
81        }

82    }

83
84    printf( "%d\n", ans );
85    return 0;
86}

87