hdu3586(树形dp 二分答案)
src:http://acm.hdu.edu.cn/showproblem.php?pid=3586
题意:给一个限制m,切断的路径权值和不超过m,单个边权值也不超过k,求最小的k使得所有叶子和根不相连
二分一个k
对于一个确定的k,dp[u]表示u的叶子全部和u分离需要的最小花费
考虑叶子节点:dp[u]=INF(不合法状态
考虑非叶子结点:一开始是没有和儿子相连,所以dp[u]=0
考虑u的一个儿子v,若(u,v)这条边是<=lim,则可以选择在消除这条边或者是在v的子树中消除,两者取一个最优解
最后判断dp[1]是否小于给定的m
#include <iostream> #include<stdio.h> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack> #include<time.h> #include<queue> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define Max(a,b) a=max(a,b) #define Min(a,b) a=min(a,b) const int inf=0x3f3f3f;//99999999; #define siz 1005 int n,m,head[siz],Enum=0,dp[siz]; struct { int w,to,ne; }edge[siz<<1]; void init() { memset(head,-1,sizeof(head)); Enum=0; } void add_edge(int a,int b,int c) { edge[Enum].to=b; edge[Enum].w=c; edge[Enum].ne=head[a]; head[a]=Enum++; } void dfs(int u,int fa,int lim) { dp[u]=0; int v,flag=0; for(int i=head[u];i!=-1;i=edge[i].ne){ v=edge[i].to; if(v==fa)continue; flag=1; dfs(v,u,lim); if(edge[i].w<=lim)dp[u]+=min(edge[i].w,dp[v]); else dp[u]+=min(inf,dp[v]); } if(flag==0)dp[u]=inf; } bool check(int lim) { for(int i=1;i<=n;i++)dp[i]=inf; dfs(1,-1,lim); return dp[1]<=m; } int main() { std::ios::sync_with_stdio(false); while(scanf("%d %d",&n,&m)&&(n||m)){// init(); int a,b,c; for(int i=1;i<=n-1;i++){ scanf("%d %d %d",&a,&b,&c); add_edge(a,b,c);add_edge(b,a,c); } int low=1,high=m,mid,ans=-1; while(low<=high){//我 tm 竟然不会二分!!! mid=(low+high)>>1; if(check(mid)==true){ans=mid;high=mid-1;} else low=mid+1; } // for(int i=1;i<=n;i++)printf("%d ",dp[i]); // printf("\n");system("pause"); printf("%d\n",ans); } return 0; } /* 7 8 1 4 3 1 3 4 4 5 5 4 6 6 3 7 2 3 2 1 */

浙公网安备 33010602011771号