1. 程式人生 > >(二分+樹形dp)wannafly28-C

(二分+樹形dp)wannafly28-C

https://ac.nowcoder.com/acm/contest/217/C msc有n個小寵物,這些寵物的家是連在一起的,更有趣的是,這些寵物的家之間的連線關係形成了一個樹的形態。 每個小寵物的習性是不太一樣的,比如說有的可能吃素,有的可能吃葷。 作為直覺系女生,msc憑著自己突出的直覺對每個小寵物都有一個關於習性的評估值,對於寵物i,它的評估值是a[i]。 考慮到習性差異過大會很難伺候,甚至寵物間會發生衝突,所以msc希望去掉至多k個連線關係使得任意兩個可以互相到達的寵物間的評估值的差的最大值儘量小。 兩個寵物(x,y)可以互相到達當且僅當存在一個序列s1,s2,…,sk-1,sk使得對於1 ≤ i < k,si與si+1之間相連且s1=x,sk=y 現在msc給出了n個小寵物的評估值a[1…n]和這棵樹的形態,msc希望你幫她求出去掉至多k個連線關係之後,任意兩個可以互相到達的寵物間的評估值的差的最大值最小是多少。

參考部落格地址

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 10;
int ai[maxn];
vector<int> E[maxn];
int n, k, t;
int f[maxn][maxn], g[maxn];
void dp(int x, int fa = 0) {
    for(register int i = 1; i <= n; i++) 
        if(ai[x] >= ai[i] && ai[x] <= (ll)ai[i] + t) f[x][i] = 0;
    for(int v : E[x]) if(v != fa) {
        dp(v, x);
        for(register int i = 1; i <= n; i++) f[x][i] += min(f[v][i], g[v] + 1);
    }
    for(register int i = 1; i <= n; i++) g[x] = min(g[x], f[x][i]);
}
int chk() {
    memset(f, 127 / 3, sizeof(f));
    memset(g, 127 / 3, sizeof(g));
    dp(1);
    return g[1];
}
int main()
{
    scanf("%d%d", &n, &k);
    for(register int i = 1; i <= n; i++) scanf("%d", &ai[i]);
    for(register int i = 1, a, b; i < n; i++) {
        scanf("%d%d", &a, &b);
        E[a].push_back(b);
        E[b].push_back(a);
    }
    ll l = 0, r = 2e9;
    while(l < r) {
        ll m = (l + r) >> 1;
        t = m;
        if(chk() > k) l = m + 1;
        else r = m;
    }
    printf("%lld\n", l);
}