题目链接:https://vjudge.net/problem/HDU-3586
题意:一棵边权树,要删掉一些边使得每个叶子结点不能到达树根,且这些边的权值<=上限Max,且边权和小于m,求最小的上限ans,如果不满足则输出-1。
思路:
属于删边的树形dp。二分枚举上限Max,查找最小的满足要求的Max,用dp[u]表示结点u的子树中叶子结点不能到u所需删除的边的最小权值和,对于结点u,其子结点v,u->v的权值为w。那么:
如果w>Max: dp[u]+=dp[v]
如果w<=Max: dp[u]+=min(w,dp[v])
对叶子结点u,dp[u]初始化为inf,对于非叶子结点u,dp[u]初始化为0,inf设为m+1,计算dp[u]过程只要dp[u]>=inf,即可提前退出。对每次Max的检测,只用判断dp[1]<=m即可。
AC code:
#include<cstdio> #include<algorithm> using namespace std; const int maxn=1005; int n,m,cnt,head[maxn],inf,Max,dp[maxn]; struct node{ int v,w,nex; }edge[maxn<<1]; void adde(int u,int v,int w){ edge[++cnt].v=v; edge[cnt].w=w; edge[cnt].nex=head[u]; head[u]=cnt; } void dfs(int u,int fa){ dp[u]=0; int flag=0; for(int i=head[u];i;i=edge[i].nex){ int v=edge[i].v,w=edge[i].w; if(v==fa) continue; flag=1; dfs(v,u); if(w>Max) dp[u]+=dp[v]; else dp[u]+=min(w,dp[v]); if(dp[u]>=inf){ dp[u]=inf; break; } } if(!flag) dp[u]=inf; } bool solve(int x){ Max=x; dfs(1,0); return dp[1]<=m; } int main(){ while(scanf("%d%d",&n,&m),n||m){ cnt=0,inf=m+1; for(int i=1;i<=n;++i) head[i]=0; for(int i=1;i<n;++i){ int u,v,w; scanf("%d%d%d",&u,&v,&w); adde(u,v,w); adde(v,u,w); } int l=1,r=1000,mid; while(l<=r){ mid=(l+r)>>1; if(solve(mid)) r=mid-1; else l=mid+1; } if(l==1001) printf("-1 "); else printf("%d ",l); } return 0; }