基环树
如果图G是连通的,并且无回路,则称G为树。我们给树任意加一条边,就出现了环,我们称之为
基环树(pseudotree)。
上面都是无向树,如果变为有向树,则可进一步分为基环内向树和基环外向树。
基环内向树
如果一个有向基环树满足每个节点出度为1,那么我们称之为基环内向树。
特性
每棵基环内向树只有一个基环和若干树枝。(反证法去证和出度为1矛盾)
OJ链接
内向基环树 拓扑+分类讨论
首先基环内向树只有一个基环和若干树枝
对于长度大于2的基环来讲,它们可以坐一桌,树枝插不进来
对于长度等于2的基环来讲,它们俩可以坐一起同时可以各自带一条树枝链,最长情况就是各自带最长的树枝链
因此我们可以通过拓扑排序剪掉树枝,拓扑后还剩若干基环(因为有可能是基环树森林,所以基环可能不唯一) 遍历得最大环长度
因为基环长度可能为2,那么我们还要维护一个最长树枝链条长度,对于每个节点的最长链条长度我们可以在拓扑的时候dp维护
代码如下
class Solution {
public:
int maximumInvitations(vector<int>& favorite) {
//建图 拓扑剪掉述职 建立反图
//拓扑后还剩若干环 遍历得最大环长度
int n = favorite.size();
vector<int> in(n);
for(auto x : favorite)
in[x]++;
queue<int> q;
vector<int> depth(n , 1);
for(int i = 0 ; i < n ; i++)
if(!in[i])
q.push(i);
while(!q.empty())
{
int f = q.front();q.pop();
if(!(--in[favorite[f]]))
q.push(favorite[f]);
depth[favorite[f]] = depth[f] + 1;
}
int max_ring = 0 , max_link = 0l;
for(int i = 0 ; i < n ; i++)
{
if(!in[i])
continue;
int r = 1 , f = favorite[i];
while(f != i)
{
in[f] = 0;
f = favorite[f];r++;
}
in[i] = 0;
if(r == 2)
{
max_link += depth[i] + depth[favorite[i]] ;
}
else
{
max_ring = max(max_ring , r);
}
}
return max(max_link , max_ring);
}
};
基环外向树
如果一个有向基环树满足每个节点入度为1,那么我们称之为基环外向树。
特性
每棵基环外向树只有一个基环和若干树枝。(反证法去证和入度为1矛盾)