In Search of Gold【二分答案+树DP】

题目链接


  题意:给一棵N个点的树,每条边有Ai、Bi权值可以选,现在问的是选K条边作为A边,其余N-1-K条边为B边,求最短直径。

  一开始的时候,想直接在树上做一个DP,但是写完之后发现不对劲,如果我们直接在树上写DP的话,由于他们的关系是相互制约的,所以确实不大好维护,因为这个dp要考虑从祖先节点的另外的方向的节点。

  所以,我二分了一个答案,假定现在直径为mid,接下去维护点u为根的子树,当选择kk个A边的时候,此时的可行解中的最小链长是多少?只要使得1节点(也就是根节点)存在合法解就可以证明此时的mid是可行的。

  所以,依然是维护一个dp,只是此时的dp是有限制的,dp[i][j]表示的是第i个节点为根的子树中,当取j个A边的时候,此时的可行解中最短的链长是多少?

  在确定可行的时候,dp方程就可以表示出来了:(前提可行解)

cop[j + kk + 1] = min(cop[j + kk + 1], max(dp[u][kk], dp[v][j] + edge[i].a)),此时加的是A边情况;

cop[j + kk] = min(cop[j + kk], max(dp[u][kk], dp[v][j] + edge[i].b)),此时加的是B边的情况。

判断可行解,就是要求他们的边的和是小于等于mid的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
namespace fastIO {
#define BUF_SIZE 100000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline bool read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror) return false;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
        return true;
    }
#undef BUF_SIZE
};
using namespace fastIO;
const int maxN = 2e4 + 7;
int N, K, head[maxN], cnt;
struct Eddge
{
    int nex, to; ll a, b;
    Eddge(int _n=-1, int _t=0, ll _a=0, ll _b=0):nex(_n), to(_t), a(_a), b(_b) {}
} edge[maxN << 1];
inline void addeddge(int u, int v, ll a, ll b)
{
    edge[cnt] = Eddge(head[u], v, a, b);
    head[u] = cnt++;
}
inline void _add(int u, int v, ll a, ll b) { addeddge(u, v, a, b); addeddge(v, u, a, b); }
int siz[maxN];
ll dp[maxN][22], cop[22], l, r, mid, ans;
void dfs(int u, int fa)
{
    for(int i=0; i<=K; i++) dp[u][i] = INF;
    dp[u][0] = 0;
    siz[u] = 0;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u);
        for(int j=0; j<=min(siz[v] + siz[u] + 1, K); j++) cop[j] = INF;
        for(int j=0; j<=min(siz[v], K); j++)
        {
            for(int kk=0; j + kk <= min(siz[u] + siz[v] + 1, K); kk++)
            {
                if(dp[u][kk] + dp[v][j] + edge[i].a <= mid) cop[j + kk + 1] = min(cop[j + kk + 1], max(dp[u][kk], dp[v][j] + edge[i].a));
                if(dp[u][kk] + dp[v][j] + edge[i].b <= mid) cop[j + kk] = min(cop[j + kk], max(dp[u][kk], dp[v][j] + edge[i].b));
            }
        }
        siz[u] += siz[v] + 1;
        for(int j=0; j<=min(siz[u], K); j++)
        {
            dp[u][j] = cop[j];
        }
    }
}
inline void init()
{
    cnt = 0; l = 1; r = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &K);
        init();
        for(int i=1, u, v, a, b; i<N; i++)
        {
            scanf("%d%d%d%d", &u, &v, &a, &b);
            _add(u, v, a, b); r += max(a, b);
        }
        ans = r;
        while(l <= r)
        {
            mid = HalF;
            dfs(1, 0);
            if(dp[1][K] <= mid)
            {
                r = mid - 1;
                ans = mid;
            }
            else l = mid + 1;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/107590417
今日推荐