HDU 3586 Information Disturbing (树形dp+二分)

题意:给你n个结点,m,然后有n-1行数据,每行三个数据a,b,c,表示切断a,b之间的联系是c。结点1是指挥部,叶子结点为前线,在花费不超过的m的基础上,求切断的点中花费最大的最小值。


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3586


题解思路:不难看出这是一道树形dp,但是这样确定这个极限值,我们可以通过二分枚举,因为两个结点中花费最大为1000,所以我们最多枚举10次,这个复杂度还是可以接受的。状态转移方程:dp[i] += min(cost[i][son], dp[son])或者dp[i] += dp[son], i表示结点i,cost[i][son]表示i结点与孩纸结点之间的花费。前一个方程为cost[i][son]的值小为我们枚举范围中的最大值,第二个自然为大于的情况,因此在状态转移时需要判断一个两者的大小关系。

附上ac代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#define Forn_m(n,m) for(int i = n; i <= m; i++)
#define ForN_m(n,m) for(int i = n; i < m; i++) 
#define MAX 1005
#define INF 1e6+50
using namespace std;
struct Edge
{
    int v, lenght;
};
int n, m;
int dp[MAX];
bool vis[MAX];
vector <Edge> vec[MAX];
void dfs(int father,int num,int root, int limit)
{
    bool flag = false;
    int nu = vec[root].size();
    vis[root] = true;
    ForN_m(0, nu)
    {
        if (!vis[vec[root][i].v])
        {
            dfs(root,i,vec[root][i].v, limit);
            flag = true;
            if (vec[root][i].lenght <= limit)
                dp[root] += min(dp[vec[root][i].v], vec[root][i].lenght);
            else
                dp[root] += dp[vec[root][i].v];
        }
    }
    if (!flag)
        if (vec[father][num].lenght <= limit)
            dp[root] = vec[father][num].lenght;
        else
            dp[root] = INF;
}
void dichotomia(int left, int right)
{
    memset(vis, 0, sizeof(vis));
    memset(dp, 0, sizeof(dp));
    int temp = (left + right) >> 1;
    dfs(-1,-1,1,temp);
    if (left == right)
        if (dp[1] <= m)
            printf("%d\n", left);
        else
            printf("-1\n");
    else if (dp[1] <= m)
        dichotomia(left, temp);
    else
        dichotomia(temp + 1, right);

}
int main()
{
    Edge temp;
    int u, t;
    while (scanf("%d%d", &n, &m) && (n != 0 || m != 0))
    {
        Forn_m(1, n)
            vec[i].clear();
        memset(vis, 0, sizeof(vis));
        ForN_m(1, n)
        {
            scanf("%d%d%d", &u, &temp.v, &temp.lenght);
            vec[u].push_back(temp);
            t = temp.v;
            temp.v = u;
            vec[t].push_back(temp);
        }
        dichotomia(1, 1000);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值