这道题千万不要一般化:先求强连通分量再把图化为 DAG 来做(我们能够很方便的得到需要添加的边的数量,但是加哪些边会变得很麻烦) 给每个定义一个起点和终点,然后按照下面的做就行了:
当整个图只有一个环的时候,不可能通过加边使得其成为强连通图!
链接相邻的两个分块(分块 A 的终点连向分块 B 的起点)
对于分块中不是起点的入度为 0 的点,建一条反向边
注意一个细节:每个点的出度必为 1,然后,其实都可以化为找分块A终点连向B起点
有什么特点?
从一个点 u 出发 DFS 遍历所有能够遍历到的点,DFS 结束的时候必定得到一个环!而且,因为每个点的出度为 1,所有遍历到的点只能形成一个环!而且这个环还是在路径的结尾,如果把这个换缩成一个点,那么我们等够得到的是一个“倒着长”的树(只存在从叶子节点到树根的节点,这个环缩成树根了)
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
const int maxn=100005;
int in[maxn],col[maxn];
vector<int>s[maxn],b,e;
int dfs(int p)//找环
{
col[p]=1;
int v=s[p][0];
if(!col[v])
return col[p]=dfs(v);
else return col[p]=p;
}
int main()
{
int a,n;
ios::sync_with_stdio(false);
while(cin>>n)
// cin>>n;
{
memset(in,0,sizeof(in));
memset(col,0,sizeof(col));
for(int i=1; i<=n; i++)
{
cin>>a;
in[a]++;
s[i].push_back(a);
}
int k=0;
for(int i=1; i<=n; i++)
{
if(!in[i])
{
b.push_back(i);
e.push_back(dfs(i));
k++;
}
}
int t=k;
for(int i=1; i<=n; i++)//这块是说刚开始没找到的,比如1-》2,2—》3,3-》1,1-》4,你从1开始如果先到2,那么4这块不会走,所以要处理一下4的情况
{
if(!col[i])
{
b.push_back(i);
e.push_back(dfs(i));
++k;
}
}
if(k==1&&t==0)//刚开始谁都没染色,如果成环的话,那么只染色一次,k=1,并且t=0,因为入度没有为0的
{
k=0;
}
cout<<k<<endl;
for(int i=0; i<k; i++)
cout<<e[i]<<" "<<b[(i+1)%k]<<endl;
for(int i=1;i<=n;i++)
{
s[i].clear();
}
e.clear();
b.clear();
}
return 0;
}