#include <cstdio> #include <vector> using namespace std; #define MAXN 10005 int n, m, cnt;//n是顶点数,m是边数,cnt是强连通分量的个数 int belg[MAXN];//存储强连通分量,其中belg[i]表示顶点i属于第belg[i]个强连通分量 int lTime[MAXN];//结束时间标记,其中numb[i]表示离开时间为i的顶点 bool flg[MAXN];//访问标志数组 vector<int> map[MAXN], unmap[MAXN];//邻接表和逆邻接表,多case的题中不要忘记初始化 vector<int> damap[MAXN];// 缩点后DAG的邻接表,多case中不要忘记初始化 //第一次深搜,用于获得lTime[1...n]的值 void dfsOne( int cur, int &sig )//注意sig这里是引用 { flg[cur] = true; int i, size = map[cur].size(); for(i=0; i<size; ++i) { if( !flg[ map[cur][i] ] ) dfsOne(map[cur][i], sig); } lTime[++sig] = cur; } //第二次深搜,用于获得belg[1...n]的值 void dfsTwo( int cur, int sig ) { flg[cur] = true; belg[cur] = sig; int size = unmap[cur].size(), i; for(i=0; i<size; ++i) { if( !flg[ unmap[cur][i] ] ) dfsTwo(unmap[cur][i], sig); } } //顶点下标从1开始 void scc() //求连通分量 { int i, sig;//sig为强连通分量的个数 memset(flg, 0, sizeof(flg)); for(sig=0, i=1; i<=n; ++i) { if( !flg[i] ) dfsOne(i, sig); } memset(flg, 0, sizeof(flg)); for(sig=0, i=n; i>=1; --i) { if( !flg[ lTime[i] ] ) { dfsTwo( lTime[i], ++sig ); } } cnt = sig; } void compress()//缩点 { int i, j, size; for(i=1; i<=n; ++i) { size = map[i].size(); for(j=0; j<size; ++j) { if( belg[i] != belg[ map[i][j] ] ) damap[ belg[i] ].push_back( belg[ map[i][j] ] ); } } } 题目是2186 用stl写方便输入,这个题目里不需要缩点,只需要确定出度就可以了,出度为0的强连通分量的节点个数为解。 强连通分量的性质是所有点之间可以互相访问,所以他们可以看做是一个点。