【POJ】3659 Cell Phone Network 树上的极小支配集——树型DP

Cell Phone Network
Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 5524
Accepted: 1984

Description

Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.

Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ AN; 1 ≤ BN; AB) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.

Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.

Input

* Line 1: A single integer: N
* Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B

Output

* Line 1: A single integer indicating the minimum number of towers to install

Sample Input

5
1 3
5 2
4 3
3 5

Sample Output

2

Source

USACO 2008 January Gold

传送门:【POJ】3659 Cell Phone Network

题目分析:树上的极小支配集——树型DP求解。
dp[ 0 ][ i ] 表示节点 i 属于支配集且子节点全被覆盖时的最小支配集大小。
dp[ 1 ][ i ] 表示节点 i 不属于支配集但是该节点被子节点覆盖且子节点全被覆盖时的最小支配集大小。
dp[ 2 ][ i ] 表示节点 i 不属于支配集且该节点未被子节点覆盖且子节点全被覆盖时的最小支配集大小。
设当前节点为u,u的子节点为v,则
dp[ 0 ][ u ] = sigma { min { dp[ 0 ][ v ] , dp[ 1 ][ v ] , dp[ 2 ][ v ] } } + 1 ;
dp[ 1 ][ u ] = sigma { min { dp[ 0 ][ v ] , dp[ 1 ][ v ] } ;
dp[ 2 ][ u ] = sigma { dp[ 1 ][ v ] } ;
其中,当且仅当dp[ 1 ][ u ]选取的子节点中至少包含了一个属于支配集的节点是才符合条件,否则设dp[ 1 ][ u ] = INF.
并且所有的dp[ 1 ][ v ]中存在不符合条件的解时,dp[ 2 ][ u ] = INF.
(这里我们设所有的INF表示不符合条件的解)。

假设我们选择其中一个节点作为根结点root,则答案为min { dp[ 0 ][ root ] , dp[ 1 ][ root ] } ;
注意不包含dp[ 2 ][ root ],因为此时根结点一定要被覆盖。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REPV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define clear( a , x ) memset ( a , x , sizeof a )

const int MAXN = 100005 ;
const int MAXE = 200005 ;
const int INF = 100005 ;

struct Edge {
	int v , n ;
	Edge ( int var = 0 , int next = 0 ) :
		v ( var ) , n ( next ) {}
} ;

Edge edge[MAXE] ;
int adj[MAXN] , cntE ;
int dp[3][MAXN] ;
int n ;

void addedge ( int u , int v ) {
	edge[cntE] = Edge ( v , adj[u] ) ;
	adj[u] = cntE ++ ;
	edge[cntE] = Edge ( u , adj[v] ) ;
	adj[v] = cntE ++ ;
}

void dfs ( int u , int p ) {
	dp[0][u] = 1 ;
	dp[1][u] = 0 ;
	dp[2][u] = 0 ;
	int flag = 0 , flag2 = 0 ;
	for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
		int v = edge[i].v ;
		if ( v == p )
			continue ;
		dfs ( v , u ) ;
		dp[0][u] += min ( dp[0][v] , min ( dp[1][v] , dp[2][v] ) ) ;
		if ( dp[0][v] <= dp[1][v] ) {
			dp[1][u] += dp[0][v] ;
			flag = 1 ;
		}
		else dp[1][u] += dp[1][v] ;
		dp[2][u] += dp[1][v] ;
		if ( dp[1][v] == INF )
			flag2 = 1 ;
	}
	if ( !flag )
		dp[1][u] = INF ;
	if ( flag2 )
		dp[2][u] = INF ;
}

void work () {
	int u , v ;
	while ( ~scanf ( "%d" , &n ) ) {
		clear ( adj , -1 ) ;
		cntE = 0 ;
		REP ( i , n - 1 ) {
			scanf ( "%d%d" , &u , &v ) ;
			addedge ( u , v ) ;
		}
		dfs ( 1 , 0 ) ;
//		REPF ( i , 1 , n )
//			printf ( "%d %d %d\n" , dp[0][i] , dp[1][i] , dp[2][i] ) ;
		printf ( "%d\n" , min ( dp[0][1] , dp[1][1] ) ) ;
	}
}

int main () {
	work () ;
	return 0 ;
}


你可能感兴趣的:(dp,poj,图论)