H Tree Partition dois pontos + ganancioso
Endereço de repetição:
https://ac.nowcoder.com/acm/contest/4370
Tópico:
Divida uma árvore em K subárvores, tome a soma de cada subárvore como uma pontuação e minimize a pontuação máxima.
Idéias básicas:
Minimize o valor máximo, dicotomia, dicotomize o valor máximo de cada pontuação de subárvore e, com avidez, use o máximo de nós possível para construir uma subárvore.Se o número de subárvores disponíveis for menor ou igual a K, o valor máximo poderá ser reduzido e O valor máximo deve ser pelo menos maior que o valor máximo de um único nó.
(Atenção especial ao problema de contorno no processo de dicotomia e anexar alguns modelos universais de dicotomia)
Código de referência:
#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;
}
Modelo de dicotomia de número inteiro:
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;
}
Modelo de dicotomia para saída de decimais
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;//保留两位;
}