• POJ 2553 The Bottom of a Graph TarJan算法题解


    本题分两步:

    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;
    }
    
    
    



  • 相关阅读:
    iOS 获取当前设备类
    iOS 字体详解
    iOS屏幕旋转总结
    CocoaPods安装和使用教程
    【iOS】build diff: /../Podfile.lock: No such file or directory
    Eclipse使用Maven构建web项目
    UIScrollView增加刷新
    Mac下打开eclipse 始终提示 你需要安装Java SE 6 Runtime
    嵌入支付宝SDK,出现“LaunchServices: ERROR: There is no registered handler for URL scheme alipay”错误
    iOS开发 传感器(加速计、摇一摇、计步器)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5306077.html
Copyright © 2020-2023  润新知