题目
最近没什么课,刷了不少题,但总是懒得写题解,再看了好多篇大佬的千篇题解后,立志以后每做一道题就写一道相应的题解
大意是给出一个n个节点,n条路的有向图(一看就知道是多个基环树的求环问题),求最小环的大小
题解
洛谷里看了几篇都是并查集求环,或者Tarjan无脑求什么最大联通分量,额,我都不会,对于环的处理只会拓扑排序(感觉最容易理解),网上找了个靠谱的拓扑排序的板子,改成最近学的链式前向星存图法(最近用的实在太多了,感觉连二维数组存图都快忘了),将拓扑的点(环不会进行拓扑排序)visit数组置为1,dfs每个viisit为0的点(就是环上的点),虽然看起来O(n*n)的复杂度,但由于每个基环树都只剩环了,找起来非常方便(dfs的话基本上就是一路走下去)
代码
#include<bits/stdc++.h>
using namespace std;
const int maxm=400000;
struct E
{
int to,nxt;
}edge[maxm];
int head[maxm],cnt,in[maxm],visit[maxm];
void add_edge(int x1,int x2)
{
edge[++cnt].to=x2;
edge[cnt].nxt=head[x1];
head[x1]=cnt;
}
void topo(int n)
{
queue<int>q;
for(int i=1;i<=n;i++) //n 节点的总数
if(in[i]==0) q.push(i); //将入度为0的点入队列
vector<int>ans; //ans 为拓扑序列
while(!q.empty())
{
int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
ans.push_back(p);
for(int i=head[p];i;i=edge[i].nxt)
{
int y=edge[i].to;
in[y]--;
if(in[y]==0)
q.push(y);
}
}
for(int i=0;i<ans.size();i++)
visit[ans[i]]=1;
}
int dfs(int m)
{
visit[m]=1;
//cout<<m<<endl;
for(int i=head[m];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(visit[y]==0)
{
return dfs(y)+1;
}
}
return 1;
}
int main()
{
int n,x1,x2,x3,ans1;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&x1);
add_edge(i,x1);
in[x1]++;
}
topo(n);
int m=maxm;
for(int i=1;i<=n;i++)
{
if(visit[i]==0)
{
m=min(m,dfs(i));
}
}
cout<<m<<endl;
}