P2661(拓扑排序找最小环)

题目

最近没什么课,刷了不少题,但总是懒得写题解,再看了好多篇大佬的千篇题解后,立志以后每做一道题就写一道相应的题解
大意是给出一个n个节点,n条路的有向图(一看就知道是多个基环树的求环问题),求最小环的大小

题解

洛谷里看了几篇都是并查集求环,或者Tarjan无脑求什么最大联通分量,额,我都不会,对于环的处理只会拓扑排序(感觉最容易理解),网上找了个靠谱的拓扑排序的板子,改成最近学的链式前向星存图法(最近用的实在太多了,感觉连二维数组存图都快忘了),将拓扑的点(环不会进行拓扑排序)visit数组置为1,dfs每个viisit为0的点(就是环上的点),虽然看起来O(n*n)的复杂度,但由于每个基环树都只剩环了,找起来非常方便(dfs的话基本上就是一路走下去)

代码

#include
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<
	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;
}

你可能感兴趣的:(#,ACM——图论)