The 2019 ICPC Asia Shanghai Regional Contest H Tree Partition 二分+贪心

H Tree Partition 二分+贪心

重现赛地址:

https://ac.nowcoder.com/acm/contest/4370

题意:

将一个树分成K棵子树,取每棵子树的和为分数,最小化分数的最大值。

基本思路:

最小化最大值,二分,二分每棵子树分数的最大值,然后每次贪心的取尽量多的节点构建子树,如果能够得到的子树数量小于等于K那么就说明最大值还能缩,并且最大值至少也要大于单个节点的最大值。

(特别注意在二分过程中的边界问题,并且附上几个万能二分模板)

参考代码:

#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define INF 0x3f3f3f3f

const int maxn = 1e5 + 10;
int n,k;
vector<int> G[maxn];
int cost[maxn];
int mid = 0,sum = 0;
int memo[maxn];
int dfs(int s,int f){
    priority_queue<int,vector<int>,less<>> pq;
    for(auto it : G[s]){
        if(it == f) continue;
        cost[s] += dfs(it,s);
        pq.push(cost[it]);
    }
    while (!pq.empty() && cost[s] > mid){
        cost[s] -= pq.top();
        pq.pop();
        sum++;
    }
    while (!pq.empty()) pq.pop();
    return cost[s];
}
signed main() {
    IO;
    int t;
    cin >> t;
    for (int cas = 1; cas <= t; cas++) {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) G[i].clear();
        for (int i = 0; i < n - 1; i++) {
            int x, y;
            cin >> x >> y;
            G[x].push_back(y);
            G[y].push_back(x);
        }
        int l = 0;
        for (int i = 1; i <= n; i++) cin >> memo[i], l = max(l, memo[i]);
        int r = 1e18;
        int ans = 0;
        while (l <= r) {
            mid = (l + r) / 2;
            for (int i = 1; i <= n; i++) cost[i] = memo[i];
            sum = 1;
            dfs(1, 0);
            if (sum <= k) r = mid - 1,ans = mid;
            else l = mid + 1;
        }
        cout << "Case #" << cas << ": " << ans << endl;
    }
    return 0;
}

整数的万能二分模板:

int binary(int n)
{
    int l = 1, r = maxn, ans = 0;
    while(l <= r)
      {
        int mid = (l + r) >> 1;
        if(c[mid] > a[n]) ans = mid, l = mid + 1;  //判断条件与ans记录位置因题而异
        else r = mid - 1;
      }
    return ans;
}

输出小数的二分模板

double binary(){
    double lb = 0 , ub = INF;
    //重复循环直到解的范围足够小;
    for(int i = 0 ; i < 100 ; i++){
        double mid = (lb + ub) / 2;
        if(C(mid)) lb = mid;
        else ub = mid;
    }
    return floor(ub*100)/100;//保留两位;
}
发布了23 篇原创文章 · 获赞 7 · 访问量 1751

猜你喜欢

转载自blog.csdn.net/weixin_44164153/article/details/104422291