HDU 3586 Information Disturbing(二分+数形DP)

本文介绍了如何使用二分搜索结合树形动态规划解决HDU 3586问题,即在限定总花费下切断士兵树状结构中所有先锋与指挥官的联系,寻找最大限制的最小值。通过设定叶子节点的代价为无穷大,并在非叶子节点中选择切断子树或根节点边的策略,最后判断1号节点的总花费是否满足条件。注意处理无穷大值时避免溢出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处,谢谢http://blog.youkuaiyun.com/acm_cxlove/article/details/7854526       by---cxlove

不知道做什么了,找个水题做做

题目:给出n个士兵,其中1号为指挥官,关系为树状结构,叶子为先锋,现在要在总花费小于m的情况切断所有的先锋与指挥官的联系,问最大的限制最小为多少

http://acm.hdu.edu.cn/showproblem.php?pid=3586 

题目要问的是最小的最大限制,必然二分答案

然后对于每一个值,树形DP判定是否可行

dp[i]表示要切断以i为根的其它所有子树的最小代价。

其中设定叶子结点的代价为无穷大

那么对于某一个非叶子结点,要切断一棵子树就有两种选择,切断以孩子为根的子树或者切断根与孩子的边。

如果根与孩子的边大于限制,那就取无穷大。

最后判断1号结点的总花费是否小于等于m

注意:无穷大不要取太大,否则会连续相加溢出

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<ctime>
#include<sstream>
#include<cassert>
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define inf 1<<20
#define N 100005
#define pi acos(-1.0)
#define pb(a) push_back(a)
#define lson step<<1
#define rson step<<1|1
using namespace std;
struct Node{
    int v,w,next;
}edge[100005];
int start[1005],tot;
int n,m,dp[1005];
void addedge(int u,int v,int w){
    edge[tot].v=v;edge[tot].w=w;
    edge[tot].next=start[u];
    start[u]=tot++;
}
void _addedge(int u,int v,int w){
    addedge(u,v,w);
    addedge(v,u,w);
}
void dfs(int u,int limit,int pre){
    bool flag=false;
    for(int i=start[u];i!=-1;i=edge[i].next){
        int v=edge[i].v,w=edge[i].w;
        if(v==pre) continue;
        flag=true;
        dfs(v,limit,u);
        dp[u]+=min(dp[v],w>limit?inf:w);
    }
    if(!flag) dp[u]=inf;
}
bool check(int limit){
    memset(dp,0,sizeof(dp));
    dfs(1,limit,-1);
   // cout<<limit<<" "<<dp[1]<<" "<<dp[2]<<" "<<dp[3]<<" "<<dp[4]<<endl;
    if(dp[1]>m) return false;
    return true;
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF&&n+m){
        tot=0;memset(start,-1,sizeof(start));
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            _addedge(u,v,w);
        }
        int low=0,high=m,mid,ok=0,ans=-1;
        while(low<=high){
            mid=(low+high)/2;
            if(check(mid)) {ans=mid;high=mid-1;}
            else low=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值