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, 0, sizeof( 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 for( int 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 for( int 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 #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, 0, sizeof( 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 for( int 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 for( int 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, 0, sizeof( 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 for( int 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 for( int 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, 0, sizeof( f ) );
63 memset( vis, 0, sizeof( vis ) );
64 DFS( 1 );
65 memset( set, 0, sizeof( set ) );
66 memset( vis, 0, sizeof( vis ) );
67
68 int ans = 0;
69 for( int 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
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, 0, sizeof( 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 for( int 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 for( int 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, 0, sizeof( f ) );
63 memset( vis, 0, sizeof( vis ) );
64 DFS( 1 );
65 memset( set, 0, sizeof( set ) );
66 memset( vis, 0, sizeof( vis ) );
67
68 int ans = 0;
69 for( int 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