POJ 2186 Popular Cows -- tarjan 缩点
来源:互联网 发布:排课系统算法 编辑:程序博客网 时间:2024/05/01 08:19
链接:
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 10010vector< 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;}
0 0
- poj 2186 Popular Cows (tarjan + 缩点)
- POJ 2186 Popular Cows -- tarjan 缩点
- POJ 2186 popular cows (tarjan + 缩点)
- POJ 2186 Popular Cows 【Tarjan+缩点】
- poj Popular Cows(tarjan +缩点)
- (tarjan缩点)poj 2186 Popular Cows
- poj 2186 Popular Cows (tarjan缩点)
- POJ 2186 -- Popular Cows【强连通分支 && Tarjan缩点】
- POJ 2186 Popular Cows tarjan缩点 强连通分量
- POJ 2186 Popular Cows (Tarjan + 缩点)
- POJ 2186 Popular Cows(tarjan缩点)
- poj 2186 Popular Cows(Tarjan)
- POJ 2186Popular Cows(Tarjan)
- poj 2186 Popular cows ( tarjan )
- poj 2186 Popular Cows tarjan
- Popular Cows - POJ 2186 Tarjan
- Popular Cows poj 2186 tarjan
- POJ-tarjan-强连通分量+缩点-Popular Cows
- mysql存储过程
- webpy+uploadify实现文件异步上传
- 归并排序
- QFE23xx揭秘:最强大的Qualcomm RF360前端芯片——更多频带,更多模式,更小的PCB尺寸
- spss Clementine12 破解方法
- POJ 2186 Popular Cows -- tarjan 缩点
- 使用jquery.upload.js实现异步上传
- api文件名
- crontab详解
- 0-1背包问题回溯法
- c++操作sqllite
- ActiveX控件注册问题
- 算法之dijkstra算法
- gdb