poj 1947 树形DP

来源:互联网 发布:php商城分销系统源码 编辑:程序博客网 时间:2024/04/30 15:40

dp[n][j] 表示第n个节点要得到一棵j个节点的子树需要切除边的最小数量。

对于n的每一个儿子节点有:

 当切除连接该儿子的边则 dp[n][j] ++;

 当不切除连接该儿子的边则 MIN = min( dp[n][j-k] , dp[son][k] );

最终 dp[n][j] = min(dp[n][j], MIN );

AC代码如下:

#include <iostream>#include <cstring>#include <cstdio>using namespace std;typedef struct{int to;int next;}Edge;int MAXN = 0x3f3f3f3f;Edge edge[302];int head[151], tot;bool mark[151];int N, P;int dp[151][151];inline int min( int a, int b ){return ( a < b ? a : b );}void add_edge( int a, int b ){edge[tot].to = a;edge[tot].next = head[b];head[b] = tot++;edge[tot].to = b;edge[tot].next = head[a];head[a] = tot++;}void DFS( int n ){mark[n] = true;for( int i = 0; i <= P; i++ ){dp[n][i] = MAXN;}dp[n][1] = 0;//注意这里的初始化:可以理解为最初的时候只有这一个点,然后慢慢的加上儿子,随意只有 dp[n][1] 符合其他不符合为MAXNfor( int i = head[n]; i != -1; i = edge[i].next ){int t =edge[i].to;if( mark[t] ){continue;}DFS( t );for( int j = P; j >= 1; j-- ){int temp = dp[n][j] + 1;for( int k = 1; k < j; k++ ){temp = min( temp, dp[n][j-k] + dp[t][k] );}dp[n][j] = temp;}}}int main(){while( scanf( "%d%d", &N, &P ) != EOF ){memset( head, -1, sizeof( head ) );memset( mark, false, sizeof( mark ) );tot = 0;for( int i = 1; i < N; i++ ){int temp1, temp2;cin >> temp1 >> temp2;add_edge( temp1, temp2 );}DFS( 1 );int ans = dp[1][P];for( int i = 2; i <= N; i++ ){ans = min( ans, dp[i][P] + 1 );}cout << ans << endl;}return 0;}


 

原创粉丝点击