题意
一棵树,最少去掉几条边,能让分割下来的一部分恰好等于p
思路
At first glance, no thought, thought for a long time, finally understand, a subject may have a variety of ways of thinking, to find their own way of thinking,
Dp[i][j] isolated rooted at I, j is the size of the subtree, obviously dp[i][1] I node degree, then is the process of merging the backpack, each of the two connecting block combination,
Need to subtract 2, is more than the statistics of the 2, tree DP easily.
dp[rt][j] = min ( dp[rt][j-k] + dp[son][k]-2 )
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f; //注意dp初始化
const int maxn = 150 + 10;
int n, p;
int dp[ maxn ][ maxn ];
int degree[ maxn ];
struct EDGE {
int to, nex, id;
} edg[ 2 * maxn ];
int cnt, sol;
int head[ maxn ];
void INit () {
cnt = 0;
sol = INF;
for ( int i = 1; i <= n; ++i )
for ( int j = 1; j <= n; ++j )
dp[ i ][ j ] = INF;
memset ( head, -1, sizeof ( head ) );
memset ( edg, 0, sizeof ( edg ) );
memset ( degree, 0, sizeof ( degree ) );
}
void AddEdge ( int u, int v ) {
edg[ cnt ].to = v;
edg[ cnt ].nex = head[ u ];
head[ u ] = cnt++;
}
void tree_dp ( int rt, int fa ) {
dp[ rt ][ 1 ] = degree[ rt ];
for ( int i = head[ rt ]; i != -1; i = edg[ i ].nex ) {
int son = edg[ i ].to;
if ( son == fa )
continue;
tree_dp ( son, rt );
for ( int j = p; j > 1; --j ) //这里是背包?
for ( int k = 1; k < j; ++k )
dp[ rt ][ j ] = min ( dp[ rt ][ j ], dp[ rt ][ j - k ] + dp[ son ][ k ] - 2 );
}
sol = min ( sol, dp[ rt ][ p ] );
}
int main () {
#ifdef LOCAL
freopen ( "in", "r", stdin );
// freopen("out","w",stdout);
#endif
while ( ~scanf ( "%d%d", &n, &p ) ) {
INit ();
for ( int i = 0, u, v; i < n - 1; ++i ) {
scanf ( "%d%d", &u, &v );
AddEdge ( u, v );
AddEdge ( v, u );
degree[ u ]++, degree[ v ]++;
}
tree_dp ( 1, -1 );
printf ( "%d\n", sol );
}
return 0;
}