题意:
一颗树各边有其对应的边权,要求切断一些边使得根与树叶失去连接。要求:切断总花费<=m,单次切断花费<=limit,求最小的limit值
思路:
先不考虑limit这个变量限制,定义dp[u]表示以u为根的子树,切断所用与叶的连接的最小花费。
切断连接的方式有两种:1.切断当前连接边,2.沿用子树内的切断方式。以这个思路进行状态转移。
转移方程:dp[u] += min( w , dp[v] );
现在加入limit这个变量限制后状态转移方程需要做一个小变动,需将那些费用>limit的边的费用提至无限大
转移方程:dp[u] += min ( w>limit?inf:w , dp[v] );
最后求解最小的limit用二分,因为这个问题limit是线性的,limit越大dp[1]越小
细节处理:
叶子节点的费用dp[u] = inf
inf不要使用太大的数,会数据溢出,使用m+1就可以了
C++代码:#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int maxm = 2010;
int n,m,tol,head[maxn],dp[maxn];
struct edge
{
int to,next,cost;
}es[maxm];
void addedge( int u , int v , int w )
{
es[tol].to = v;
es[tol].cost = w;
es[tol].next = head[u];
head[u] = tol++;
}
void dfs( int u , int f , int k )
{
dp[u] = 0; bool leaf = true;
for ( int i=head[u] ; i!=-1 ; i=es[i].next )
{
int v = es[i].to,w = es[i].cost;
if ( v!=f )
{
leaf = false;
dfs( v , u , k );
dp[u] += min( dp[v] , w>k?m+1:w );
}
}
if ( leaf ) dp[u] = m+1;
}
bool ok( int k )
{
dfs( 1 , 0 , k );
if ( dp[1]<=m ) return true;
else return false;
}
int main()
{
while( scanf( "%d%d" , &n , &m )==2 )
{
if ( n==0&&m==0 ) break;
tol = 0; memset( head , -1 , sizeof(head) );
for ( int i=1 ; i<n ; i++ )
{
int u,v,w; scanf ( "%d%d%d" , &u , &v , &w );
addedge( u , v , w );
addedge( v , u , w );
}
int l=1,r=1000,mid,ans=-1;
while( l<=r )
{
mid = (l+r)>>1;
if ( ok(mid) )
{
ans = mid;
r = mid-1;
}
else
{
l = mid+1;
}
}
printf( "%d\n" , ans );
}
return 0;
}