poj_2553 强连通分支&出度为0的点

题目大意

N个点的有向图中,定义“好点”为: 
从该点v出发可以到达的所有点u,均有一条路径使得u可达v。 
求出图中所有的“好点”,并按照顺序从小到大输出出来。

题目分析

图存在多个强连通分支,强连通分支内的所有点的行为可以视为一个点的行为:若强连通分支可以到达其他强连通分支,则该强连通分支内的所有点均可以到达其他分支;若强连通分支可以被其他点到达,则该强连通分支内的所有点均可以被其他点到达。因此,将图的强连通分支缩成一个点是一个经常会进行的操作。 
    将强连通分支缩成一个点之后,形成一个有向无环图。在有向无环图中,出度为0的点所代表的强连通分支,显然满足“好点”的要求;而出度不为0的点,显然存在它可以到达的点,但这些点不能到达它,故不满足“好点”的要求。因此,“好点”就是出度为0的点代表的强连通分支内的点。

实现(c++)

#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<set>
using namespace std;
#define MAX_NODE 5005
#define min(a, b) a < b? a:b
#define max(a, b) a > b? a:b

vector<int> gGraph[MAX_NODE];
stack<int> gStack;
int gDfn[MAX_NODE];
int gLow[MAX_NODE];

bool gVisited[MAX_NODE];
bool gInStack[MAX_NODE];
int gClusterOfNode[MAX_NODE];
int gIndex;
int gClusterIndex;

//Tarjan算法求强连通分支
void Tarjan(int u){
	gDfn[u] = gLow[u] = ++gIndex;
	gInStack[u] = true;
	gVisited[u] = true;
	gStack.push(u);

	for (int i = 0; i < gGraph[u].size(); i++){
		int v = gGraph[u][i];
		if (!gVisited[v]){
			Tarjan(v);
			gLow[u] = min(gLow[u], gLow[v]);
		}
		else if (gInStack[v]){
			gLow[u] = min(gLow[u], gDfn[v]);
		}
	}
	if (gDfn[u] == gLow[u]){
		int v;
		do{
			v = gStack.top();
			gStack.pop();
			gInStack[v] = false;
			gClusterOfNode[v] = gClusterIndex;
		} while (v != u);
		++gClusterIndex;
	}
}
vector<set<int> >gLinkFrom;	//每个强连通分支,入点集合
vector<set<int> > gLinkTo;	//每个强连通分支,出点集合
void ReconstructGraph(int nodes, int clusters){
	gLinkFrom.clear();
	gLinkFrom.resize(clusters);
	gLinkTo.clear();
	gLinkTo.resize(clusters);

	for (int u = 1; u <= nodes; u++){
		for (int i = 0; i < gGraph[u].size(); i++){
			int v = gGraph[u][i];
			int uc = gClusterOfNode[u];
			int vc = gClusterOfNode[v];
			if (uc != vc){	//注意!!!
				gLinkTo[uc].insert(vc);
				gLinkFrom[vc].insert(uc);
			}
		}
	}
}

int main(){
	int n, r;
	while (scanf("%d", &n) && n != 0){

		scanf("%d", &r);

		for (int i = 0; i <= n; i++){
			gGraph[i].clear();
		}

		int u, v;
		for (int i = 0; i < r; i++){
			scanf("%d %d", &u, &v);
			gGraph[u].push_back(v);
		}

		memset(gVisited, false, sizeof(gVisited));
		memset(gInStack, false, sizeof(gInStack));
		gIndex = gClusterIndex = 0;
		for (int i = 1; i <= n; i++){
			if (!gVisited[i])
				Tarjan(i);
		}

		ReconstructGraph(n, gClusterIndex);	//将染色后的图进行重构(即设置强连通分支)

		set<int> zero_outdegree_cluster_id;	//出度为0的强连通分支的集合
		for (int i = 0; i < gClusterIndex; i++){
			if (gLinkTo[i].empty()){	//出度为0,强连通分支
				zero_outdegree_cluster_id.insert(i);
			}
		}

		//遍历每个点,判断其是否属于那些出度为0的强连通分支
		for (int u = 1; u <= n; u++){
			if (zero_outdegree_cluster_id.find(gClusterOfNode[u]) != zero_outdegree_cluster_id.end()){
				printf("%d ", u);
			}
		}

		printf("\n");
	}
	return 0;
}
时间: 2024-12-17 22:28:42

poj_2553 强连通分支&出度为0的点的相关文章

POJ1236 (强连通分量缩点求入度为0和出度为0的分量个数)

Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13804   Accepted: 5507 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a li

poj 2553 The Bottom of a Graph 【强连通图中出度为0点】

题目:poj 2553 The Bottom of a Graph 题意:大概题意是给出一个有向图,求强连通缩点以后出度为0的点. 分析:入门题目,先强连通缩点,然后表示出度为0的,枚举输出即可. #include <cstdio> #include <vector> #include <iostream> #include <stack> #include <cstring> using namespace std; const int N =

poj 1236 Network of Schools(连通图入度,出度为0)

http://poj.org/problem?id=1236 Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13046   Accepted: 5215 Description A number of schools are connected to a computer network. Agreements have been developed among those scho

POJ 2553--The Bottom of a Graph【scc缩点构图 &amp;&amp; 求出度为0的scc &amp;&amp; 输出scc中的点】

The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9575   Accepted: 3984 Description We will use the following (standard) definitions from graph theory. Let V be a nonempty and finite set, its elements being called ver

poj Popular Cows(tarjan +缩点)

Language: Default Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24384   Accepted: 10007 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up

poj_2186 强连通分支

题目大意 有N头牛,他们中间有些牛会认为另外一些牛“厉害”,且这种认为会传递,即若牛A认为牛B“厉害”,牛B认为牛C“厉害”,那么牛A也认为牛C“厉害”.现给出一些牛的数对(x, y)表示牛x认为牛y厉害.那么,求出所有的牛都认为该牛“厉害”的牛的个数. 题目分析 牛之间的关系,形成一个有向图.其中存在一些强连通分支,若强连通分支内的一个牛被所有牛认为“厉害”,那么整个强连通分支内的牛都被认为“厉害”.因此,将强连通分支合并为一个点,对图重构.     重构后的图为一个简单的有向图,题目转换为寻

POJ 2186 -- Popular Cows【强连通分支 &amp;&amp; Tarjan缩点】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27198   Accepted: 10963 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &

poj_1236 强连通分支

题目大意 有N个学校,这些学校之间用一些单向边连接,若学校A连接到学校B(B不一定连接到A),那么给学校A发一套软件,则学校B也可以获得.现给出学校之间的连接关系,求出至少给几个学校分发软件,才能使得所有的学校均可以获得软件:以及,至少需要添加几条单向边连接学校,才能使得给这些学校中任何一所发软件,其余的学校均可以收到. 题目分析 在一个图中,强连通分支内的任何一个点被“发软件”,则分支内的所有点均可以获得,因此首先求出强连通分支,将强连通分支合并为一点来看.     重构之后的图若只有一个点,

POJ 1236--Network of Schools【scc缩点构图 &amp;&amp; 求scc入度为0的个数 &amp;&amp; 求最少加几条边使图变成强联通】

Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13325   Accepted: 5328 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a li