//求图中环的个数 //由于图中每个点的出度只有1,所以不存在一个点处于两个环的交点 //因此,求环的个数时每个只需要考虑一次便可得出结果 //由于数据规模庞大,写成递归形式容易暴栈 //在读边的过程中先对自环进行预处理,之后对每个点进行不同的染色,对它的下一个点也染同样的颜色 //这样染下去如果发现下一个要染的点和正在染的颜色相同,则说明存在一个环 //换染色起点的同时也需要更换新的染色,才能保证对环的判断正确 #include<iostream> #include<cstring> using namespace std; int next[1000001];//指向下一结点的指针 int vis[1000001];//对每个结点进行不同的标记 int ans,n,ringID,p; void search() { for(int i = 1;i <= n;++i) { if(vis[i] > 0) continue; p = i; ++ringID;//对每一种环进行一种不同的标记,新的起点必须更换新的染色 while(vis[p] == 0)//当前结点未被染色 { vis[p] = ringID;//染色 p = next[p];//指向下一个点 if(vis[p] == ringID)//下一个点的颜色和当前染色相同,则说明存在一个环 ++ans; } } } int main() { //freopen("in.txt","r",stdin); while(scanf("%d",&n) != EOF) { ans = 0; ringID = 1; memset(vis,0,sizeof(vis)); for(int i = 1;i <= n;++i) { scanf("%d",&next[i]); if(next[i] == i) { vis[i] = ringID++;//先对自环进行预处理 ans++; } } search(); printf("%d/n",ans); } return 0; }