本题分两步:
1 使用Tarjan算法求全部最大子强连通图。而且标志出来
2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的全部点,都是解集。
Tarjan算法就是模板算法了。
这里使用一个数组和一个标识号,就能够记录这个顶点是属于哪个子强连通图的了。
然后使用DFS递归搜索全部点及其边,假设有边的还有一个顶点不属于本子强连通图。那么就说明有出射的边。
有难度的题目:
#include <stdio.h> #include <stdlib.h> #include <vector> #include <stack> using namespace std; const int MAX_VEC = 5005; int n, m; vector<int> gra[MAX_VEC]; stack<int> stk; int dfn[MAX_VEC];//tarjan算法记录深度探索得到的标号 int low[MAX_VEC];//tarjan算法记录回溯得到的最低顶点编号 bool inStk[MAX_VEC];//记录是否在栈里面,也能够记录是否被訪问过了 int connectGrp[MAX_VEC];//标志所属的连通子图标号 == connectNum int vecNum;//顶点标号 int connectNum;//最大强连通子图标号 int out[MAX_VEC];//出度记录 void tarjan(int u) { dfn[u] = low[u] = vecNum++; stk.push(u); inStk[u] = 1; for (int i = 0; i < (int)gra[u].size(); i++) { int v = gra[u][i]; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]);//两处的不同,和含义不同 } else if (inStk[v]) low[u] = min(dfn[v], low[u]);//两处的不同 } if (low[u] == dfn[u]) { ++connectNum; while (stk.size()) { int v = stk.top(); stk.pop(); inStk[v] = false; connectGrp[v] = connectNum; if (u == v) return; } } } void solveConnect() { memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(inStk, 0, sizeof(inStk)); for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } } void dfsCountOut(int u) { inStk[u] = true; //记录是否被訪问过了 for (int i = 0; i < int(gra[u].size()); i++) { int v = gra[u][i]; if (connectGrp[u] != connectGrp[v]) { out[connectGrp[u]]++;//这个组的出度添加; connectGrp[] == connectNum } if (!inStk[v]) dfsCountOut(v);//深度优先,不须要使用额外空间 } } void countConnectOut() { memset(inStk, 0, sizeof(inStk)); //这里仅仅记录是否被訪问过的了。 memset(out, 0, sizeof(out)); for (int i = 1; i <= n; i++) { if (!inStk[i]) dfsCountOut(i); } } int main() { int u, v; while (scanf("%d", &n) && n) { connectNum = 0; vecNum = 1; scanf("%d", &m); for (int i = 1; i <= n; i++) gra[i].clear(); while (stk.size()) stk.pop(); //清零。重中之重 for (int i = 0; i < m; i++) { scanf("%d %d", &u, &v); gra[u].push_back(v); //有向图 } solveConnect(); countConnectOut(); for(int i = 1; i <= n; ++i) if(out[connectGrp[i]] == 0) printf("%d ", i); putchar(' '); } return 0; }