/*
Problem: Maximum People That Can Sit Around a Table With Favorite Neighbors
Company Tag: Barclays OA
Problem Statement:
We have N people.
Each person likes exactly one other person.
A person will attend only if they sit next to the person they like.
The table is circular.
We need to find the maximum number of people who can attend.
Constraints:
1 <= N <= 100000
1 <= likes[i] <= N
Each person likes exactly one person.
Simple Brute Force:
Try every subset of people and every circular seating order.
Why Brute Force Fails:
There are too many subsets and permutations.
This is impossible for N up to 100000.
Better Idea:
Think of this as a directed graph.
Each person points to the person they like.
The answer can come from:
1. One big cycle of size at least 3.
2. Mutual pairs with chains attached to both people.
For mutual pair a <-> b:
We can attach the longest chain ending at a
and the longest chain ending at b.
Final answer:
max(largest cycle size, total contribution of all mutual pairs)
Dry Run:
likes = [2, 1, 2, 3, 4]
1 likes 2
2 likes 1
3 likes 2
4 likes 3
5 likes 4
Mutual pair:
1 <-> 2
Chain:
5 -> 4 -> 3 -> 2
Seating:
1 - 2 - 3 - 4 - 5
Answer = 5
Time Complexity:
O(N)
Space Complexity:
O(N)
*/
#include <bits/stdc++.h>
using namespace std;
int maximumPeopleAroundTable(vector<int>& likes) {
int n = likes.size();
vector<int> fav(n);
vector<int> indegree(n, 0);
for (int i = 0; i < n; i++) {
fav[i] = likes[i] - 1;
indegree[fav[i]]++;
}
queue<int> q;
// depth[i] means the longest chain length ending at person i.
vector<int> depth(n, 1);
// First remove all people who are not part of any cycle.
for (int i = 0; i < n; i++) {
if (indegree[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
int person = q.front();
q.pop();
int nextPerson = fav[person];
// person can be placed before nextPerson, so update the chain length.
depth[nextPerson] = max(depth[nextPerson], depth[person] + 1);
indegree[nextPerson]--;
if (indegree[nextPerson] == 0) {
q.push(nextPerson);
}
}
int largestCycle = 0;
int mutualPairTotal = 0;
vector<int> visited(n, 0);
for (int i = 0; i < n; i++) {
if (indegree[i] > 0 && !visited[i]) {
vector<int> cycle;
int current = i;
while (!visited[current]) {
visited[current] = 1;
cycle.push_back(current);
current = fav[current];
}
int cycleSize = cycle.size();
if (cycleSize == 2) {
int a = cycle[0];
int b = cycle[1];
/*
For a mutual pair, we can take the best incoming chain
on both sides.
*/
mutualPairTotal += depth[a] + depth[b];
} else {
largestCycle = max(largestCycle, cycleSize);
}
}
}
return max(largestCycle, mutualPairTotal);
}
int main() {
int n;
cin >> n;
vector<int> likes(n);
for (int i = 0; i < n; i++) {
cin >> likes[i];
}
cout << maximumPeopleAroundTable(likes) << endl;
return 0;
}