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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑上传的文件大小超过限制怎么办 文件最大不超过200m怎么办 抖音上传文件太大怎么办 下载ppt变成php文件怎么办 数据库bak文件损坏了怎么办? wps文档大小超出上传限制怎么办 手机百度用微盘下载不了文件怎么办 无法读取源文件或磁盘怎么办 文件中转站未安装上传控件怎么办 手机外国网址网速太差怎么办 istpng里显示不出图片怎么办 电脑上保持登录状态后怎么办 电脑打游戏闪退怎么办 实训老师教不好怎么办 善心汇损失的钱怎么办 去陌生的地方怕传销怎么办 被执行人不提供财产线索怎么办 宽带ip地址改了怎么办 移动宽带恢复出厂设置了怎么办 移动100兆网速慢怎么办 手机显示无法解析dns地址怎么办 台式电脑宽带连接不上怎么办 电信宽带账号登录密码忘记了怎么办 电信校园宽带超时了怎么办 宽带连接账号密码忘了怎么办 移动宽带路由器上不了网怎么办 移动宽带太卡了怎么办 电信adsl密码忘记了怎么办 移动宽带无法连接网络怎么办 移动宽带电视无信号怎么办 联通网线故障电话打不通怎么办 w10系统ip地址错误怎么办 移动流量太贵了怎么办 修改wifi密码ip地址怎么办 苹果6s接电话声音小怎么办 k歌录音器失败怎么办 想报警但不能说话怎么办 微粒贷要家人电话怎么办 4g网络信号差怎么办 手机移动网络信号不好怎么办 移动的4g网络差怎么办