有n个点n-1条边组成的连通图,问可以最少分成多少个联通块,并且每个块里的权值和小于k...权值和是块里的边权和。
对于一个节点u来言,他的一个子节点v可能和他一起也可能不一起,类似于01背包的感觉。
dp[i][j]代表i点所在权值和为j的最小联通块数量...
对于u的一个子节点来言就是做背包的过程,要不要把这个子节点加入到u里...
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define mod 1000000007
#define inf 0x3f3f3f3f
int dp[120][120];
struct edge
{
int u,v,w,next;
}edge[230];
int head[120],tot,k,used[120];
void init()
{
memset(dp,inf,sizeof(dp));
memset(head,-1,sizeof(head));
memset(used,0,sizeof(used));
tot=0;
}
void add(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u)
{
used[u]=1;
dp[u][0]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(used[v]) continue;
dfs(v);
for(int j=k;j>=0;j--)
{
int tmp=inf;
for(int x=0;x<=k;x++)
tmp=min(tmp,dp[v][x]);
dp[u][j]+=tmp;//默认u,v不在一起
for(int x=0;x<=j-w;x++)//尝试合并
{
dp[u][j]=min(dp[u][j],dp[u][j-w-x]+dp[v][x]-1);
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
init();
int n,u,v,w;
scanf("%d %d",&n,&k);
for(int i=1;i<n;i++)
{
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(1);
int ans=inf;
for(int i=0;i<=k;i++)
{
ans=min(ans,dp[1][i]);
}
printf("Case %d: %d\n",cas,ans);
}
return 0;
}