1. 程式人生 > >Wannafly挑戰賽28 C msc的寵物

Wannafly挑戰賽28 C msc的寵物

Wannafly挑戰賽28 msc的寵物

題意:

給定一棵樹,樹上每個節點有權值,要求刪除最多k條邊使得所有聯通塊的最大值和最小的差最大的最小

分析:

最小化最大值,很明顯是二分最大的差值D了
轉化一下題目其實就是將樹上的節點分成k個聯通塊,使得所有聯通塊的最大值和最小的差最大的最小。

狀態:

  • f[x] 表示至少刪除F[x] 個才能使得x子樹差值不超過D
  • g[x][u] 表示至少刪除g[x][u] 個才能使得子樹最大值為a[u]

狀態轉移:

設y是x的子節點

  • 如果 a[y] <= a[u] <= a[y]+D,g[x][u] = min(f[y]+1,g[x][u]);(直接斷開這條邊或者留下這條邊)
  • 否則g[x][u] = f[y]+1; (直接斷開這條邊)
  • f[x] = min(g[x][u]);

參考程式碼


#include <bits/stdc++.h>
#define Pb push_back
using namespace std;
typedef long long LL;
// const int    INF = 0x7FFFFFFF;
const LL     INFF =1e15;
const int maxn = 1000+10;
LL f[maxn],g[maxn][maxn];
LL a[maxn];
LL val[maxn];

std::vector<
int> G[maxn]; LL D; int n,k; void dfs(int node,int fa){ for(int i = 1;i <= n; ++i) { if(a[node] <= a[i] && a[i] <= a[node]+ D) g[node][i] = 0; else g[node][i] = INFF; } for(int i = 0;i < (int) G[node].size();++i){ int v = G[node][i]
; if(v == fa) continue; dfs(v,node); for(int u = 1;u <= n; ++u){ if(a[v] <= a[u] && a[u] <= a[v]+D) g[node][u] += min(f[v]+1,g[v][u]); else g[node][u] += f[v]+1; } } f[node] = INFF; for(int i = 1;i <= n; ++i) f[node] = min(f[node],g[node][i]); } LL check(LL mid){ D = mid; dfs(1,-1); // cout<<D<<" "<<f[1]<<endl; // cout<<f[1]<<endl; return f[1]; } int main(void) { cin>>n>>k; for(int i = 1;i <= n; ++i) scanf("%lld",&a[i]);//,val[i] = a[i]; // sort(val+1,val+n+1); for(int i = 1,v,u;i < n; ++i){ scanf("%d%d",&u,&v); G[u].Pb(v); G[v].Pb(u); } LL l = 0,r = 1000000000+2; while(r >= l){ LL mid = (r+l)>>1; if(check(mid) <= k)// < 說明差值可以縮小,> 說明差值過小 r = mid-1; else l = mid+1; } cout<<l<<endl; return 0; }