HDU 6769 In Search of Gold 二分答案+树形DP

原题链接:https://acm.hdu.edu.cn/showproblem.php?pid=6769

题意

有一棵树,每条边都有两个权值a,b可以选择,一共可以选择k条a权值,n-1-k条b权值,问最小的树的直径是多少?

分析

非常好的一道题,可以让人基本上弄懂树形背包的复杂度。

先考虑状态,根据套路容易写出 f [ u ] [ j ] f[u][j] f[u][j]代表u节点选择j条a权值的边到最远叶子结点距离的最小值,这样状态转移就可以轻松推出

f [ u ] [ i + j + 1 ] = m i n ( f [ u ] [ i + j + 1 ] , f [ u ] [ i ] , f [ v ] [ j ] + a ) f[u][i+j+1]=min(f[u][i+j+1], f[u][i], f[v][j]+a) f[u][i+j+1]=min(f[u][i+j+1],f[u][i],f[v][j]+a)

f [ u ] [ i + j ] = m i n ( f [ u ] [ i + j ] , f [ u ] [ i ] , f [ v ] [ j ] + b ) f[u][i+j]=min(f[u][i+j], f[u][i], f[v][j]+b) f[u][i+j]=min(f[u][i+j],f[u][i],f[v][j]+b)

此时还是存一个 t m p [ j ] tmp[j] tmp[j]来暂时表示当前层的转移,这样不会造成dp反复更新,而且复杂度也是NK的。

接着我们怎么和直径扯上关系呢,如果想直接靠这个转移得到最小直径是不行的,状态还不够表示,因此考虑二分答案,我们直接在合并时判断当前最长链是否超过mid,如果超过则不合并答案,最后检查根节点的最长链长度是否超过mid,答案是满足单调性的。

总时间复杂度也就是 O ( N K l o g A n s ) O(NKlogAns) O(NKlogAns)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;

#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\n'

namespace StandardIO {
    template<typename T>
    inline void read(T &x) {
        x = 0; T f = 1;
        char c = getchar();
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }

    template<typename T>
    inline void write(T x) {
        if (x < 0) putchar('-'), x *= -1;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + '0');
    }
}

using namespace StandardIO;
int n, k, h[N], cnt;
struct Edge {
    int to, next, a, b;
}e[N];
void add(int u, int v, int a, int b) {
    e[cnt].to = v;
    e[cnt].a = a;
    e[cnt].b = b;
    e[cnt].next = h[u];
    h[u] = cnt++;
}
ll f[N][25], tmp[25];
int siz[N];
void dfs(int x, int fa, ll len) {
    siz[x] = 0;
    for (int i = 0; i <= k; i++) f[x][i] = 0;
    for (int i = h[x]; ~i; i = e[i].next) {
        int v = e[i].to;
        if (v == fa) continue;
        dfs(v, x, len);
        int K = min(siz[x] + siz[v] + 1, k);
        for (int j = 0; j <= K; j++) tmp[j] = len + 1;
        for (int j = 0; j <= min(siz[x], K); j++) {
            for (int l = 0; l <= siz[v] && j + l <= K; l++) {
                if (f[x][j] + f[v][l] + e[i].a <= len) {
                    tmp[j + l + 1] = min(tmp[j + l + 1], max(f[x][j], f[v][l] + e[i].a));
                }
                if (f[x][j] + f[v][l] + e[i].b <= len) {
                    tmp[j + l] = min(tmp[j + l], max(f[x][j], f[v][l] + e[i].b));
                }
            }
        }
        for (int j = 0; j <= K; j++) f[x][j] = tmp[j];
        siz[x] += siz[v] + 1;
    }
}
inline void solve() {
    int T; read(T); while (T--) {
        read(n), read(k);
        for (int i = 0; i <= n; i++) h[i] = -1;
        cnt = 0;
        ll r = 0, l = 1;
        for (int i = 1; i <= n - 1; i++) {
            int u, v, a, b;
            read(u), read(v), read(a), read(b);
            add(u, v, a, b);
            add(v, u, a, b);
            r += max(a, b);
        }
        while (l <= r) {
            ll mid = (l + r) >> 1;
            dfs(1, 0, mid);
            if (f[1][k] <= mid) r = mid - 1;
            else l = mid + 1;
        }
        printf("%lld\n", l);
    }
}
signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
毕设新项目基于python3.7+django+sqlite开发的学生就业管理系统源码+使用说明(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 学生就业管理系统(前端) ## 项目开发环境 - IDE: vscode - node版本: v12.14.1 - npm版本: 6.13.4 - vue版本: @vue/cli 4.1.2 - 操作系统: UOS 20 ## 1.进入项目目录安装依赖 ``` npm install ``` ## 2.命令行执行进入UI界面进行项目管理 ``` vue ui ``` ## 3.编译发布包(请注意编译后存储路径) #### PS:需要将编译后的包复制到后端项目的根目录下并命名为'static' 学生就业管理系统(后端) ## 1.项目开发环境 - IDE: vscode - Django版本: 3.0.3 - Python版本: python3.7.3 - 数据库 : sqlite3(测试专用) - 操作系统 : UOS 20 ## 2.csdn下载本项目并生成/安装依赖 ``` pip freeze > requirements.txt pip install -r requirements.txt ``` ## 3.项目MySQL数据库链接错误 [点击查看解决方法](https://www.cnblogs.com/izbw/p/11279237.html)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值