@Acqua
2019-01-25T06:18:58.000000Z
字数 2071
阅读 931
动态规划 二分答案 独立解题
给定一棵结点数为的树,要求砍掉一些边(带非负权),使所有叶结点与根结点不连通。限制最高花费为,求砍掉的边中最大权值的最小值。
尝试极端方法:严格证明法。
“最大值最小化”,
使用二分答案。
数据结构为树,
使用图论模板。
启发式思维[1],
使用树形DP:设表示对于以结点为根的子树,以删除子边删除父边的决策使所有叶结点与根结点不连通的总代价。
删除父边就不用管下面的连接情况,
。(证伪:“只选择”或“继承的选择”都可以断绝的子树中所有叶结点与的联系)
不删父边就要删掉所有子边(易证:对于有子节点的点,其子节点一定是叶结点或叶结点的祖先),
。
最终答案为,因为根结点没有父边。
更正:dp[u]表示对于以结点为根的子树,使所有叶结点与根结点不连通的总代价。
对于有,答案为。
,
。
不可删除,
在搜索更新时把暂时赋值为。
叶结点不可删除子边,
叶结点。
- ,说明小了,以至于无法删去某些效果能够“一条顶多条”的大权边,否则按照规则,非最优解不可能成为答案,故。
- ,说明刚好,故。
- ,说明可能还不够小,以至于删除了一些过大的边取得了更优结果,故。
因为是非法结果,所以不参与答案统计,所以把和的更新安排在一起。
// La Pluie#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=1e3+5,inf=1e6+1;struct edge{int v,w,next;}e[N<<1];int head[N],k,dp[N],n,m;void adde(int u,int v,int w){e[k]=(edge){v,w,head[u]};head[u]=k++;}void dfs(int u,int f,int d){int son=0;for(int i=head[u];i!=-1;i=e[i].next){int v=e[i].v,w=e[i].w;if(v==f) continue;son++;dfs(v,u,d);dp[u]+=min(dp[v],w>d?inf:w);}if(!son) dp[u]=inf;}int main(){while(~scanf("%d%d",&n,&m)&&(n||m)){memset(head,-1,sizeof(head));k=1;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,ans=-1;while(l<=r){int mid=l+r>>1;memset(dp,0,sizeof(dp));dfs(1,0,mid);if(dp[1]<=m) ans=mid,r=mid-1;else l=mid+1;}printf("%d\n",ans);}return 0;}