zoukankan      html  css  js  c++  java
  • HDU 3586 二分答案+树形DP判定

    HDU 3586

    『Link』HDU 3586

    『Type』二分答案+树形DP判定

    ✡Problem:

    给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit。第一行输入的n,m;之后是n-1条边,我们要求最小的limit。(1leq nleq 1000,1leq mleq 10^6)

    ✡Answer:

    这个直接想二分limit,用树形dp求出断掉所有叶子的最小值,之后判断dp[1]<=m(dp[i]表示要切断以i为根的其它所有子树的最小代价)还是挺难想的。但是直接一个for循环拍过去的话也是可以过的(2.5s)之后也就可以想到用二分优化了。
    但是这个INF还是挺难弄的,大了会溢出,小了又会wa,要仔细想下,正好是1000 *1000再加一点就行了。

    『Complexity』(O(nlogn))

    ✡Code:

    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <set>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define cle(a,v) memset(a,(v),sizeof(a))
    #define fo(i,a,b) for(int i=(a);i<=(b);i++)
    #define fd(i,a,b) for(int i=(a);i>=(b);i--)
    #define ll long long
    const int maxn = 1e3 + 7, INF = 1000007;
    int n, m, u, v, w, tot, head[maxn], dp[maxn];
    struct Edge {
    	int v, w, next;
    } edges[maxn << 1];
    void added(int u, int v, int w) {
    	edges[tot] = Edge{v, w, head[u]};
    	head[u] = tot++;
    }
    void init() {
    	cle(head, -1);
    	tot = 0;
    }
    void dfs(int u, int fa, int mid) {
    	int flag = 0;
    	dp[u] = 0;
    	for (int i = head[u]; ~i; i = edges[i].next) {
    		int v = edges[i].v;
    		int w = edges[i].w;
    		if (v == fa) continue;
    		flag = 1;
    		dfs(v, u, mid);
    		if (w > mid) {
    			dp[u] += dp[v];
    		}
    		else {
    			dp[u] += min(w, dp[v]);
    		}
    	}
    	if (flag == 0) dp[u] = INF;
    }
    int main() {
    	freopen("1.in", "r", stdin);
    	while (scanf("%d%d", &n, &m), n + m) {
    		init();
    		int l = 1, r = 1;
    		for (int i = 1; i < n; i++) {
    			scanf("%d%d%d", &u, &v, &w);
    			r = max(r, w);
    			added(u, v, w); added(v, u, w);
    		}
    		int dd = r;
    		while (l <= r) {
    			int mid = l + r >> 1;
    			dfs(1, -1, mid);
    			if (dp[1] <= m) {
    				r = mid - 1;
    			}
    			else {
    				l = mid + 1;
    			}
    		}
    		if (l < 1 || l > dd) {
    			l = -1;
    		}
    		printf("%d
    ", l);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    AndRodi Strudio中的按钮时件
    Intent(三)向下一个活动传递数据
    Intent(二)隐式调用intent
    用PopupWindow做下拉框
    环形进度条
    Android Studio分类整理res/Layout中的布局文件(创建子目录)
    Android无需申请权限拨打电话
    使用ViewPager切换Fragment时,防止频繁调用OnCreatView
    定制 黑色描边、白色背景、带圆角 的背景
    Android 底部弹出Dialog(横向满屏)
  • 原文地址:https://www.cnblogs.com/s1124yy/p/7300957.html
Copyright © 2011-2022 走看看