HDU

来源:互联网 发布:js substr 编辑:程序博客网 时间:2024/05/22 08:19

传送门
//题意: 1是总部, 要切断所有叶结点和总部的联系, 每天变有个花费, 要保证总花费在小于m的情况下的最小的limit(每条边的花费要小于limit).
//思路: 这个前提看似非常矛盾, 因为加入砍去两条边权为5的比砍去一条边长为6的limit的要更小一点, 但是有可能总和又要超过m,所以要综合考虑到两部分. 那么采用二分答案, 然后check当前这个答案, 如果合适就减小当前的答案. 然后check用树形dp做, dp[i] 代表 砍掉i小面所有的叶子结点的联系在mid的限制下的最小花费和. 然后细节请看代码

AC Code

const int maxn = 1e3+5;int cnt,head[maxn],dp[maxn];int n,m;struct node{    int to,w,next;}e[maxn*maxn];void add(int u,int v,int w){    e[cnt] = (node){v,w,head[u]};    head[u] = cnt++;}void dfs(int u,int fa,int mid){    int flag = 0;    for(int i=head[u]; ~i ; i =e[i].next){        int to = e[i].to;        if(fa == to) continue;        flag = 1;        dfs(to,u,mid);        if(e[i].w > mid) dp[u] += dp[to]; //如果这条边不满足.那么只有从它的儿子里面选.        else dp[u] += min(dp[to], e[i].w); //否则在儿子中与当前这条边取一个较小的值.    }    if(!flag) dp[u] = maxn*maxn;  //这个取大一点,反正要比m大.}void solve(){    while(~scanf("%d%d",&n,&m) && n && m){        if(n == 1){            printf("0\n");            continue;        }        cnt = 0; Fill(head,-1);        int mx = 0;        for(int i=1;i<n;i++){            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add(u,v,w); add(v,u,w);            mx = max(mx,w);        }        int l = 0, r = mx,res = inf;        while(r - l >= 0){            int mid = (r+l)>>1;            Fill(dp,0); dfs(1,-1,mid);            if(dp[1] <= m ){                r = mid - 1;                res = mid;            }            else l = mid + 1;        }        if(res == inf) printf("-1\n");        else printf("%d\n",res);    }}
原创粉丝点击