树上简单问题->巡逻(洛谷3629)
题意:
一颗树,从点1出发,初始代价是访问每个点1次回到点1。现在要加k <= 2条边,求加了边后的最小代价。
分析:
当k = 1时,代价就是初始代价-直径 + 1
当k = 2时,目前还不能理解
void solve(){
int n, k;
cin >> n >> k;
vector<vector<int>> al(n + 1);
for (int i = 1; i < n; ++i){
int u, v;
cin >> u >> v;
al[u].emplace_back(v);
al[v].emplace_back(u);
}
vector<int> dist(n + 1);
function<void(int, int, int)> dfs = [&](int u, int p, int d){
dist[u] = d;
for (const auto& v : al[u]){
if (v != p){
dfs(v, u, d + 1);
}
}
};
int now = 1;
dfs(now, 0, 0);
now = max_element(dist.begin(), dist.end()) - dist.begin();
dfs(now, 0, 0);
int ans = 2 * (n - 1) - *max_element(dist.begin(), dist.end()) + 1;
cout << ans << '\n';
}
24.5.21 更新
如何理解k == 2的情况呢?就是k=1的时候造的环会节省一些边只走一次,但是第二次建了环以后,为了让第二个环一定走一次,第一次节省的边可能会需要走两次,才能满足这个条件,所以只要把走两次的边,从贡献中删去即可。为了达到这种计算效果,把第一次节省的边都存下来(记录父亲节点和直径的一个端点),然后在第二次遍历的时候,如果当前的边已经在第一次被节省了,那么在第二次中这个直径不会再被节省了,就要把贡献删去!将权重设为-1完美匹配这种情况。
void solve(){
int n, k;
cin >> n >> k;
vector<vector<int>> al(n + 1);
for (int i = 1; i < n; ++i){
int u, v;
cin >> u >> v;
al[u].push_back(v);
al[v].push_back(u);
}
vector<int> dist(n + 1);
vector<int> path(n + 1);
function<void(int, int, int, bool)> dfs = [&](int u, int p, int d, bool cal_path = false){
dist[u] = d;
if (cal_path){
path[u] = p;
}
for (const auto& v : al[u]){
if (v != p){
dfs(v, u, d + 1, cal_path);
}
}
};
dfs(1, 0, 0, false);
int point_1 = max_element(dist.begin(), dist.end()) - dist.begin();
dfs(point_1, 0, 0, true);
int point_2 = max_element(dist.begin(), dist.end()) - dist.begin();
int dist_d1 = dist[point_2];
if (k == 1){
cout << (n - 1) * 2 - (dist_d1) + 1 << '\n';
}
else{
dist.clear();
vector<bool> in_path(n + 1);
for (int u = point_2; u; u = path[u]){
in_path[u] = 1;
}
int dist_d2 = 0;
vector<int> weight(n + 1, 1);
vector<int> dp(n + 1);
function<void(int, int)> dpCal = [&](int u, int p){
for (const auto&v : al[u]){
if (v != p){
if (in_path[u] && in_path[v]){
weight[v] = -1;
}
dpCal(v, u);
dist_d2 = max(dist_d2, dp[u] + dp[v] + weight[v]);
dp[u] = max(dp[u], dp[v] + weight[v]);
}
}
};
dpCal(1, 0);
cout << (n - 1) * 2 - (dist_d1 + dist_d2) + 2 << '\n';
}
}