hdu 3586 树形dp +二分

来源:互联网 发布:淘宝瑜伽服模特是谁 编辑:程序博客网 时间:2024/05/29 11:19

题意:给n个节点的树,要求使叶子节点与根断开,割掉的边的权值和不超过m。求这些被割边的权值最大中的最小。

dp 【u】+=min(dp【v】,w),w 为 u 到 v 的权值。

如果w 大于二分的 mid dp【u】+=dp【v】;

二分枚举边权。

#include<cstdio>#include<cstring>#include<cmath>#include<iostream>using namespace std;#define FF  freopen("Input.txt","r",stdin)#define ll long long#define inf 1000020const int N=1010;int head[N];struct Point{    int v,w;    int next;}edge[N*2];int tot;inline void init(){    memset(head,-1,sizeof(head));    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++;}int dfs(int u,int k,int s){    int sum=0;    bool flag=false;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].v;        int w=edge[i].w;        if(v==s) continue;        flag=true;        int tmp=dfs(v,k,u);        if(w<=k) sum+=min(tmp,w); //w 满足mid         else sum+=tmp; //不满足    }    if(!flag) sum=inf;    return sum;}int main(){    //FF;    int n,i,m;    while(~scanf("%d%d",&n,&m))    {        if(n==0&&m==0) break;        init();        int l=1000000,r=0;        for(i=1;i<n;i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add(a,b,c); add(b,a,c);            l=min(c,l);r=max(r,c); //l 和r记录边权的最小和最大值。        }        int ans=-1;        while(l<=r)        {            int mid=(l+r)>>1;            int sum=dfs(1,mid,0);            if(sum<=m) { ans=mid; r=mid-1;} //如果满足条件,更新答案。            else l=mid+1;        }        printf("%d\n",ans);    }    return 0;}


原创粉丝点击