zoukankan      html  css  js  c++  java
  • Information Disturbing (树型DP + 二分)

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

    题意:

    给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit

    思路:

    dp[x] 代表 x 为根的子树总的花费

    需要求最小上限lim,容易想到二分去求解

    状态转移方程怎么去确定?

    设当前边权为 w

    ( lim >= w)    dp[u] += min(dp[v] , w )   (可以选择断了当前的边或者不断)

    ( lim < w)      dp[u] += dp[v]                 ( 只能选择不断当前边权)

    最后去判断下总的花费是否满足题意

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <string.h>
    #include <vector>
    #include <map>
    #include <stack>
    #include <set>
    #include <queue>
    #include <math.h>
    #include <cstdio>
    #include <iomanip>
    #include <time.h>
    #include <bitset>
    #include <cmath>
    #include <sstream>
    
    #define LL long long
    #define INF 10000100
    #define ls nod<<1
    #define rs (nod<<1)+1
    
    const double eps = 1e-10;
    const int maxn = 2e4 + 10;;
    const LL mod = 1e9 + 7;
    
    int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
    using namespace std;
    
    // 一棵有n个节点的有根树,1为根节点,边带权,
    // 表示删掉这条边的代价。现在要删掉一些边,使叶子节点不能到达根节点。
    // 但是,每次删除的边的代价不能超过limit,删掉的边的总代价不能超过m
    // 求最小的limit的可能取值。
    
    struct edge{
        int v,w,nxt;
    }e[maxn<<1];
    
    int head[maxn];
    int f[maxn];
    int cnt;
    int n,m;
    
    inline void add_edge(int u,int v,int w) {
        e[++cnt].v = v;
        e[cnt].w = w;
        e[cnt].nxt = head[u];
        head[u] = cnt;
    }
    
    inline void dfs(int x,int fa,int lim) {
        int fl = 1;
        f[x] = 0;
        for (int i = head[x];~i;i = e[i].nxt) {
            int v = e[i].v;
            if (v == fa)
                continue;
            fl = 0;
            dfs(v,x,lim);
            if (e[i].w <= lim)
                f[x] += min(f[v],e[i].w);
            else
                f[x] += f[v];
            if (f[x] >= 10000100)
                f[x] = 10000100;
        }
        if (fl)
            f[x] = 10000100;
    }
    
    inline bool check(int x) {
        dfs(1,0,x);
        return (f[1] <= m);
    }
    
    
    int main() {
        ios::sync_with_stdio(false);
        while (cin >> n >> m) {
            if (n == 0 && m == 0)
                break;
            cnt = 0;
            memset(head,-1, sizeof(head));
            for (int i = 1;i < n;i++) {
                int u,v,w;
                cin >> u >> v >> w;
                add_edge(u,v,w);
                add_edge(v,u,w);
            }
            if (n == 1) {
                cout << 0 << endl;
                continue;
            }
            int l = 1,r = 1000;
            int ans = -1;
            while (l <= r) {
                int mid = (l + r) >> 1;
                if (check(mid)) {
                    ans = mid;
                    r = mid - 1;
                }
                else
                    l = mid + 1;
            }
            cout << ans << endl;
        }
        return 0;
    }
  • 相关阅读:
    SAP的一些HR函数
    如何在sap的screen中使用ListBox
    关于SAP的SD的定价公式的资料(强力推荐,有时间我会进行翻译)
    如何设计和使用自定义的权限对象(自定义权限检查函数)
    [转载]ASP.NET面试题收集
    [转载]sql in与exists区别
    删除A数据表中的一行数据时,不小心将表名写成了B,现在想恢复B中刚删除的的着一行数据怎么办
    删除A数据表中的一行数据时,不小心将表名写成了B,现在想恢复B中刚删除的的着一行数据怎么办
    oracle优化总结经验
    oracle优化总结经验
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/12363516.html
Copyright © 2011-2022 走看看