题意:
给出n个人以及他的父亲,询问家族关系中最长的一条链,可以有环。
思路:
每个人的儿子可以有多个,但是父亲只有一个或者没有。先考虑简单的情况,没有环的话,就类似于森林,建一条儿子指向父亲的单向边,从叶子出发topu,记录一下每个点向下延申的最大距离即可。如果有环的话,不难发现,环上挂着的链的方向都是指向环的,答案就会变为环的周长+挂着的最长的一条链的长度。和之前一样从叶子topu,环上有链的点都记录了该点所链的最大长度,topu结束后,dfs遍历环统计一下环的周长和最长链。
#include <bits/stdc++.h>
#define _debug(x) cerr<<#x << " = " << x<<endl
using namespace std;
typedef long long ll;
//typedef _int128 lll;
const int MOD = 0;
//const double eps = 1e-3;
const int MAXN = 200000 + 59;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f;
const double eps = 1e-9;
unordered_map<string, int> id;
int n, m, ans;
int ind[MAXN];
string sn, fn1, _son, _of, fn2;
struct Edge {
int v, nx;
} ed[MAXN << 2];
int head[MAXN], cntEd;
void addEdge(int u, int v) {
ed[cntEd] = {v, head[u]};
head[u] = cntEd++;
}
int val[MAXN];
queue<int>q;
bool out[MAXN];
void topu(){
while (!q.empty()){
int u=q.front();
// printf("u:%d\n",u);
out[u]= true;
q.pop();
for(int i=head[u];~i;i=ed[i].nx){
int v=ed[i].v;
ind[v]--;
val[v]=max(val[v],val[u]+1);
ans=max(ans,val[v]);
if(!ind[v]){
q.push(v);
}
}
}
}
int tmp;
int r;
void dfs(int u){
out[u]=true;
tmp=max(tmp,val[u]);
r++;
for(int i=head[u];~i;i=ed[i].nx){
int v=ed[i].v;
if(out[v])continue;
dfs(v);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
memset(head, -1, sizeof head);
cntEd = 0;
cin >> n;
for (int i = 1, u, v; i <= n; ++i) {
cin >> sn >> fn1 >> _son >> _of >> fn2;
fn1 = sn + fn1;
fn2 = sn + fn2;
if (!id[fn1])id[fn1] = ++m;
if (!id[fn2])id[fn2] = ++m;
v = id[fn1];
u = id[fn2];
addEdge(v, u);
ind[u]++;
}
ans=1;
for(int i=1;i<=m;i++){
if(!ind[i]){
q.push(i);
}
}
topu();
// printf("%d\n",ans);
for(int i=1;i<=m;i++){
if(!out[i]){
tmp=0;
r=0;
dfs(i);
// printf("r:%d\n",r);
ans=max(ans,tmp+r);
}
}
printf("%d\n",ans);
return 0;
}