【题目描述】:
有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
现在给出一个有向图。结点个数N(<=1000)(编号1~N),边数M(<=5000)。请你按照从小到大的顺序输出最大的强连通分量结点编号。
【输入描述】:
第一行N和M 以下M行,每行两个空格隔开的整数表示一条有向边;
【输出描述】:
输出一行,最大的强连通分量的结点(由小到大输出)
【样例输入】:
10 20
2 2
5 3
8 5
3 4
8 7
10 10
10 6
7 7
2 8
3 2
8 1
3 8
1 7
8 10
7 5
6 4
9 2
8 6
7 5
1 8
【样例输出】:
1 2 3 5 7 8
【时间限制、数据范围及描述】:
时间:1s 空间:256M
N<=1000, M<=5000
tarjan模板如下:
#include "iostream" #include "cstdio" #include "cstdlib" #include "stack" #include "algorithm" using namespace std; #define MAXN 1005 #define MAXM 5005 int n,m; /*********************** 链式前向星 ***********************/ struct ENode{ int v,w,next; }edge[MAXM]; //边集 int p[MAXN],ec; //点集和边集计数 void InsertE(int u, int v, int w){ //插入边 edge[++ec].v = v; edge[ec].w = w; edge[ec].next = p[u]; p[u] = ec; } /*********************** Tarjan算法基础 搜索强连通分量 ***********************/ int dfn[MAXN],cTime,low[MAXN]; //时间戳,时间戳计数,祖先时间。 int gid[MAXN],gc; // 分量数组,分量计数。 bool ins[MAXN]; stack<int> sTar; //入栈标志,辅助栈 void Tarjan(int u){ dfn[u]=low[u]=++cTime; //时间戳与祖先时间初始化 ins[u]=1; sTar.push(u); //入栈 for(int i=p[u];i;i=edge[i].next){ //递归处理所有子结点 int v=edge[i].v; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); //利用子孙,更新能回指的祖先时间戳 } else if(ins[v]) //记录U能回指的最早祖先的时间戳 low[u]=min(low[u],dfn[v]); } if(low[u]>=dfn[u]){ //判断U是否分量的根 gc++; int i; do{ i=sTar.top(); ins[i]=0; gid[i]=gc; sTar.pop(); //分量出栈 }while(i!=u); //出栈至当前结点,包括当前结点 } } int main() { freopen("connect.in","r",stdin); freopen("connect.out","w",stdout); int x,y,c=0; cin >> n >> m; for(int i=0;i<m;i++){ cin >> x >> y; InsertE(x,y,0); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); int a[MAXN]={0}; for(int i=1;i<=n;i++){ a[gid[i]]++; if(a[gid[i]]>a[a[0]])a[0]=gid[i]; } for(int i=1;i<=n;i++) if(gid[i]==a[0]) cout << i << ' '; cout << endl; return 0; }