CF51F Caterpillar
IV. CF51F Caterpillar
初级图论。
题目要求不能存在环,我们自然地想到将所有 E-BCC 缩成一个点。缩点后整张图会变成一棵森林,先处理每一棵树,再用连通块数量
考虑确定主链后如何用最少的操作使得一棵树变成毛毛虫。
对于除了主链以外的节点,考虑它是否作为最终挂在主链旁边的叶子。将主链看成根,具有祖先后代关系的点对不能同时被选中作为叶子,因为此时后代和主链之间隔了一个祖先,说明它到主链的距离
因此相当于选择最多的节点使得这些节点之间没有祖先后代关系。我们的决策是选择所有叶子,因为若一个非叶子被选,我们一定可以取消选择它,并选择它的所有儿子,这样一定更优。不断调整即可得到该结论。
因此,最终保留的节点为所有主链上的节点和我们选中作为叶子的节点。这意味着对于某条路径
容易发现,当
因此,设原图的叶子数量为
时间复杂度
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int n, m;
vector<pair<int, int>> e[N];
vector<int> g[N];
int dn, dfn[N], low[N], top, stc[N], cn, col[N];
void form(int id) {cn++; for(int x = 0; x != id; ) col[x = stc[top--]] = cn;}
void tarjan(int id, int eid) {
stc[++top] = id, dfn[id] = low[id] = ++dn;
for(auto _ : e[id]) {
if(_.second == eid) continue;
int it = _.first;
if(!dfn[it]) {
tarjan(it, _.second), low[id] = min(low[id], low[it]);
if(low[it] > dfn[id]) form(it);
}
else low[id] = min(low[id], dfn[it]);
}
if(!eid) form(id);
}
int ans, comp, vis[N], dis[N];
vector<int> cur;
void find(int id) {
cur.push_back(id), vis[id] = 1;
for(int it : g[id]) if(!vis[it]) find(it);
}
void dfs(int id, int ff) {
dis[id] = dis[ff] + 1;
for(int it : g[id]) if(it != ff) dfs(it, id);
}
void deal(int id) {
if(g[id].empty()) return ans++, void();
cur.clear(), find(id);
dfs(id, 0);
int u = id, leaf = 0;
for(int it : cur) if(dis[it] > dis[u]) u = it;
dfs(u, 0);
for(int it : cur) if(dis[it] > dis[u]) u = it;
for(int it : cur) leaf += g[it].size() == 1;
ans += dis[u] + leaf - 2;
}
int main() {
#ifdef ALEX_WEI
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
e[u].push_back({v, i});
e[v].push_back({u, i});
}
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, 0);
for(int i = 1; i <= n; i++)
for(auto _ : e[i])
if(col[i] != col[_.first])
g[col[i]].push_back(col[_.first]);
for(int i = 1; i <= n; i++) if(!vis[i]) deal(i), comp++;
cout << n - ans + comp - 1 << endl;
return cerr << "Time: " << clock() << endl, 0;
}
/*
2022/5/26
start coding at 6:41
finish debugging at 7:00
*/