POJ 2186 Popular Cows -- tarjan 缩点

链接:

POJ 2186 Popular Cows

题意:

每一头牛都希望在牛群里面备受瞩目,在一个牛群中有N头牛(1<=N<=10000),你被给予M(1<=M<=50000)个关系对,形式如(A,B),这意味着A牛认为B牛比它更受欢迎,由于这种欢迎度是满足传递性的,那么若是A牛认为B牛更受欢迎,B牛认为C牛更受欢迎,那么A牛也会认为C牛更受欢迎。你的任务是计算出被所有牛受欢迎的牛的个数。

输入:

第一行两个整数 N 和 M

第2 到 M + 1 行,两个分开的数 A,B,意味着 A认为 B 更受欢迎。

输出:

被所有牛认为受欢迎的牛的个数

比如输入:

3 3

1 2

2 1

2 3

比如输出:

1

隐藏信息:

3号牛是最后欢迎的

来源于:

USACO 2007 秋季赛

思路:

用tarjan算法求得强连通分量后,将每个SCC缩点,得到的图为 DAG 图,然后寻找出度为 0 的节点(数出该分量中的节点个数),若出度为 0 的节点不止一个,则不存在答案。

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;

#define MAX_SIZE 10010

vector< int > Graph[MAX_SIZE];
vector< int > NewGraph[MAX_SIZE]; // 缩点后的图

int nodeBelongToSCC[MAX_SIZE]; // 每个节点属于哪个SCC中

int Stack[MAX_SIZE];
bool nodeIsInStack[MAX_SIZE];
int stack_pointer = 0;

int Lows[MAX_SIZE];
int Dfns[MAX_SIZE];

int node_num = 0;   // 图中节点得到个数
int edge_num = 0;
int find_time = 0;  // 每个节点的发现时间

int scc_num = 0;    // 记录 scc 的个数

void find_scc( int start_node ){

    find_time++;
    Lows[start_node] = Dfns[start_node] = find_time;

    stack_pointer++;
    Stack[stack_pointer] = start_node;
    nodeIsInStack[start_node] = true;

    for( int i = 0; i < Graph[start_node].size(); ++i ){
        int end_node = Graph[start_node][i];
        //若是end_node尚未被访问
        if( Dfns[end_node] == 0 ){
            find_scc( end_node );
            Lows[start_node] = min( Lows[start_node], Lows[end_node] );
        }
        //若end_node在栈中,也就是start_node -> end_node是返祖边
        else if( nodeIsInStack[end_node] ){
            Lows[start_node] = min( Lows[start_node], Dfns[end_node] );
        }
    }

    //若是start_node的时间戳与Lows相等在构成SCC
    if( Dfns[start_node] == Lows[start_node] ){
        scc_num++;
        int pop_node_index = Stack[stack_pointer];
        stack_pointer--;
        nodeIsInStack[pop_node_index] = false;
        // 设定每个节点的SCC
        nodeBelongToSCC[pop_node_index] = scc_num;

        while( start_node != pop_node_index ){
            pop_node_index = Stack[stack_pointer];
            nodeIsInStack[pop_node_index] = false;
            stack_pointer--;
            nodeBelongToSCC[pop_node_index] = scc_num;
        }
    }
}

// 缩点
void shrink(){
    for( int start_node = 1; start_node <= node_num; ++start_node ){

        int start_scc = nodeBelongToSCC[start_node];
        for( int index = 0; index < Graph[start_node].size(); ++index ){

            int end_node = Graph[start_node][index];
            int end_scc = nodeBelongToSCC[end_node];
            // 若是起始 SCC 与 目标 SCC 相同
            if( start_scc != end_scc ){
                bool exists = false;
                for( int i = 0; i < NewGraph[start_scc].size(); ++i ){
                    if( NewGraph[start_scc][i] == end_scc )
                        exists = true;
                }
                // 该分量尚未和目标分量有边相连
                if( exists == false ){
                    NewGraph[start_scc].push_back( end_scc );
                }
            }
        }
    }
}

void init_values(){
    memset( nodeBelongToSCC, 0, sizeof( nodeBelongToSCC ) );
    memset( Stack, 0, sizeof( Stack ) );
    memset( nodeIsInStack, false, sizeof( nodeIsInStack ) );
    memset( Lows, 0, sizeof( Lows ) );
    memset( Dfns, 0, sizeof( Dfns ) );
}

// 统计出度为 0 的分量里面节点的个数
void solve(){
    int count_num = 0;
    int ans_scc = 0;
    for( int i = 1; i <= scc_num; ++i ){
        if( NewGraph[i].size() == 0 ){
            ans_scc = i;
            count_num++;
        }
    }
    int ans = 0;
    if( count_num == 1 ){
        for( int i = 1; i <= node_num; ++i ){
            if( nodeBelongToSCC[i] == ans_scc ){
                ans++;
            }
        }
    }
    cout << ans << endl;
}

int main(){

    init_values();
    int start_node, end_node;
    cin >> node_num >> edge_num;

    for( int i = 1; i <= edge_num; ++i ){
        cin >> start_node >> end_node;
        Graph[start_node].push_back( end_node );
    }

    for( int start_node = 1; start_node <= node_num; ++start_node ){
        //该节点尚未被访问到
        if( Dfns[start_node] == 0 ){
            find_scc( start_node );
        }
    }
    shrink();
    solve();
}

Kosaraju算法解:

#include <vector>
#include <fstream>
#include <cstring>
#include <iostream>
using namespace std;
const int MAX_SIZE = 10005;
vector< int >G[MAX_SIZE];
vector< int >GT[MAX_SIZE];
vector< int >stack;
bool isVisit[MAX_SIZE];
int par[MAX_SIZE];
int tree[MAX_SIZE];
int N, M;
int countVertex = 0;
int parentNum = 0;

void initG_GT(){
	memset( par, 0, sizeof(par) );
	cin>>N>>M;
	for( int i = 1; i <= M; ++i ){
		int start, end;
		cin>>start>>end;
		G[start].push_back( end );
		GT[end].push_back( start );
	}
}

void DFS_G( int index ){
	isVisit[index] = true;
	for( int i = 0; i < G[index].size(); ++i ){
		if( !isVisit[G[index][i]] ) DFS_G( G[index][i] );
	}
	stack.push_back( index );
}

void DFS_GT( int index, const int& parent ){
	isVisit[index] = true;
	par[index] = parent;
	++tree[parent];
	for( int i = 0; i < GT[index].size(); ++i ){
		if( !isVisit[GT[index][i]] ) DFS_GT( GT[index][i], parent );
	}
}

void Kosaraju(){
	for( int i = 1; i <= N; ++i ){
		if( !isVisit[i] ){
			DFS_G( i );
		}
	}
	memset( isVisit, false, sizeof( isVisit ) );
	memset( tree, 0, sizeof( tree ) );
	for( int i = stack.size() - 1; i >= 0; --i ){
		if( !isVisit[stack[i]] ){
			parentNum++;
			DFS_GT( stack[i], parentNum );
		}
	}
}

void cal(){
	int flag = 0;
	int ans = 0;
	memset( isVisit, false, sizeof( isVisit ) );
	for( int i = 1; i <= N; ++i ){
		for( int j = 0; j < G[i].size(); ++j ){
			int x = G[i][j];
			if( par[i] != par[x] ) isVisit[par[i]] = true;
		}
	}
	for( int i = 1; i <= parentNum; ++i ){
		if( !isVisit[i] ){
			++flag;
			ans = i;
		}
	}
	if( flag == 1 ) cout<<tree[ans]<<endl;
	else cout<<"0"<<endl;
}

int main()
{
	initG_GT();
	Kosaraju();
	cal();
	return 0;
}

POJ 2186 Popular Cows -- tarjan 缩点

时间: 2024-10-10 07:28:05

POJ 2186 Popular Cows -- tarjan 缩点的相关文章

POJ 2186 Popular Cows tarjan缩点算法

题意:给出一个有向图代表牛和牛喜欢的关系,且喜欢关系具有传递性,求出能被所有牛喜欢的牛的总数(除了它自己以外的牛,或者它很自恋). 思路:这个的难处在于这是一个有环的图,对此我们可以使用tarjan算法求出强连通分量,把强连通分量压缩成一个点,构成一个新的图,这个图一定是没有环的,如果有环就跟强连通分量的矛盾了.压缩成无环图以后这个图里面的点是不具有方向的,我们通过遍历每个节点所能连到的点,如果两点的id值即所在的强连通分量区域不同时,我们就把这个节点的出度加1.最后去找那些出度等于0的点,如果

Poj 2186 Popular Cows (Tarjan)

题目链接: Poj 2186 Popular Cows 题目描述: 有n只牛,牛之间存在一些关系,比如a认为b很受欢迎,b认为c很受欢迎,这样呢,a也会认为c很受欢迎,问根据给出的关系,有多少头牛被其他所有的牛都认为是受欢迎的? 解题思路: 对于一个有向无环图来说,其中有且仅有一个点出度为零,那么这个特殊的点,可以由其他任何点到达.那么接下来我们直接对所给的图进行强连通分量划分,然后把每个强连通分量看做一个点,判定出度为零的点有几个,如果有一个就输出这个点对应的强连通分量含有的节点个数,否则为零

Poj 2186 Popular Cows(Tarjan 强连通缩点)

传送门:Poj 2186 题意:给你n头牛,m种关系,A牛认为B牛是popular的,B牛认为C牛是popular的,则A也认为C是popular的,问最终有几头被所有牛认为是popular的牛 题解:强连通缩点基础题(虽然我Tarjan和缩点都是对的,但是最终讨论判断的时候写垮了(写了3天....还不是你懒!!!!过年划水这么多天缩点后找出度为零的点个数.然后讨论是否有这样子的点,如果没有则全都是(整个都是强连通图),如果只有一个,那么那个强连通分量所含的牛的个数就是所求解,如果有多个那么都是

poj 2186 Popular Cows 强连通缩点

[题意]:给出一群牛中,一头牛认为另一头牛受欢迎的m对关系,关系式可以传递的,即若a认为b受欢迎,b认为c受欢迎,那么a也认为c受欢迎.求最多有多少头牛被所有的牛认为受欢迎. [思路]:把这些关系形成的强连通图缩成点,就形成了一有向无环图,这个图里的出度为0的点(有且只有一个)就是被所有牛认为受欢迎的点,说明若这个点原来是强连通图就要求出这个强连通图里的总点数, 1 #include<iostream> 2 #include<stdio.h> 3 #include<strin

poj 2186 Popular Cows 【强连通】

题目:poj 2186 Popular Cows 题意:n头牛,其中存在一些牛相互崇拜,具有传递性,问有多少头牛是被其他所有牛崇拜的. 分析:建立一个有向图,然后强连通缩点,之后求出度为0的点,假如存在多个,那么ans = 0,因为缩点之后如果x崇拜y,x也崇拜z,那么肯定y和z不能互相崇拜,不满足. 然后求出度为0的这个点缩点前环上有多少个点就ans AC代码: #include <cstdio> #include <vector> #include <iostream&g

POJ 2186 Popular Cows --强连通分量

题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样,这个有向图就变成了一个有向无环图. 在这个新的图中,只需知道出度为0的点有几个即可. 如果出度为0的点超过1个,则输出0:否则输出出度为0的点所代表的那个强连通分支的分量数即可. 用Tarjan求强连通分量 代码: #include <iostream> #include <cstdio&g

POJ 2186 Popular Cows (强连通分量)

POJ 2186 Popular Cows 链接:http://poj.org/problem?id=2186 题意:每头奶牛都梦想着成为牧群中最受奶牛仰慕的奶牛.在牧群中,有N 头奶牛,1≤N≤10,000,给定M 对(1≤M≤50,000)有序对(A, B),表示A 仰慕B.由于仰慕关系具有传递性,也就是说,如果A 仰慕B,B 仰慕C,则A 也仰慕C,即使在给定的M 对关系中并没有(A, C).你的任务是计算牧群中受每头奶牛仰慕的奶牛数量. 思路:首先可以知道,在同一个强连通分量内的点一定互

强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)

poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且可以传递, 即1欢迎2不代表2欢迎1, 但是如果2也欢迎3那么1也欢迎3. 求被所有牛都欢迎的牛的数量. 限制: 1 <= N <= 10000 1 <= M <= 50000 思路: Kosaraju算法, 看缩点后拓扑序的终点有多少头牛, 且要判断是不是所有强连通分量都连向它. Kosaraju算法,分拆完连通分量后,也完成了拓扑序. /*poj 2186

poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】

题目地址:http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27496   Accepted: 11059 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