【强连通分量】10204 - 谁是孽角子

【强连通分量】10204 - 谁是孽角子

Time Limit: 1000MS
Memory Limit: 2048KB

本题由南山卢致远原创!在此感谢!

NSOI 选孽角子了,负责扫地的孽角子,由于大家风度太好,所有都不愿意去争取,经过叶老师的再三思考,决定来一次投票推荐,参加投票的有N个人,将他们按1 — N编号。自己是憋憋推荐自己的、注意,一个人可以投多个人。Nsoi之间的信任存在传递性,如果,A支持B,那么A也会支持B支持的人。如果某个人接获得 所有人的推荐,那么他就有可能是孽角子,这个任务交给了致标,致标抓于马下,所以向你求助,任务统计所有可能是孽角子的人。

输入 :
 Glover.in
 第一行 N,M  有N个人参加了投票,共投M票。 N<=10000 , M<=40000
 接下来 M 行,每行两个正整数 a , b ; 表示  a 推荐 b;  a <= N && b
<= N ;

输出:
Glover.out
第一行 :ANS_N  表示有ANS_N个人有机会成为孽角子。
接下来  ANS_N 行, 每行一个数 ,表示有机会成为孽角子人的编号。

样例 :
Glover.in
7  10
1 2
2 4
4 3
2 3
3 6
3 5
5 6
6 7
7 5
1 6
Glover.out
3
5
6
7

 1 # include<cstdio>
 2 # include<cstring>
 3 # include<stack>
 4 # include<algorithm>
 5 # include<iostream>
 6 using namespace std;
 7 const int N=30000+10;
 8 const int M=60000+10;
 9 stack<int>S;
10 int n,m,ecnt,scc_cnt,dfs_clock,tot,out_degree,cur;
11 int fist[N],next[M],v[M],pre[N],low[N],scc_no[N],size[N],out[N];
12 void built(int a,int b){
13     ++ecnt;
14     v[ecnt]=b;
15     next[ecnt]=fist[a];
16     fist[a]=ecnt;
17 }
18 int check(int a,int b){
19     for(int e=fist[a];e!=-1;e=next[e])
20     if(v[e]==b)return 0;
21     return 1;
22 }
23 void init(){
24     int a,b;
25     memset(fist,-1,sizeof(fist));
26     scanf("%d%d",&n,&m);
27     for(int i=1;i<=m;i++){
28         scanf("%d%d",&a,&b);
29         if(check(a,b))
30         built(a,b);
31     }
32 }
33 int dfs(int u){
34     int lowu=pre[u]=++dfs_clock;
35     S.push(u);
36     for(int e=fist[u];e!=-1;e=next[e])
37     if(!pre[v[e]])
38     lowu=min(lowu,dfs(v[e]));
39     else if(!scc_no[v[e]])
40     lowu=min(lowu,pre[v[e]]);
41     low[u]=lowu;
42     if(low[u]==pre[u]){
43         scc_cnt++;
44         for(;;){
45             int x=S.top();S.pop();
46             scc_no[x]=scc_cnt;
47             if(x==u)break;
48         }
49     }
50     return low[u];
51 }
52 void find_scc(){
53     memset(pre,0,sizeof(pre));
54     memset(low,0,sizeof(low));
55     for(int i=1;i<=n;i++)
56     if(!pre[i])dfs(i);
57 }
58 void work(){
59     for(int i=1;i<=n;i++)for(int e=fist[i];e!=-1;e=next[e])
60     if(scc_no[i]!=scc_no[v[e]])out[scc_no[i]]++;
61     for(int i=1;i<=scc_cnt;i++)if(out[i]==0){out_degree=i;cur++;}
62     if(cur!=1){printf("0");return;}
63     for(int i=1;i<=n;i++)if(scc_no[i]==out_degree)tot++;
64     printf("%d\n",tot);
65     for(int i=1;i<=n;i++)if(scc_no[i]==out_degree)printf("%d\n",i);
66 }
67 int main(){
68     init();
69     find_scc();
70     work();
71     return 0;
72 }
时间: 2024-10-12 14:43:13

【强连通分量】10204 - 谁是孽角子的相关文章

BZOJ 2438 杀人游戏(强连通分量)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2438 题意:一位冷血的杀手潜入某村庄,并假装成 平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身 安全并知道谁是杀手

【强连通分量+概率】Bzoj2438 杀人游戏

Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少? Sulotion 最优的询问对象是,把强连通分量缩成一个点(问其中一个可推

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

POJ 2186 Popular Cows 强连通分量模板

题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> using namespace std; const int maxn = 50005; int n, m; struct Edge { int v, next;

USACO network of school 强连通分量

这个题的意思是有一个有向图, 每个顶点可以发送软件到与其相连的顶点上, 现在问1,至少发送给几个顶点能满足所有顶点都收到软件, 2:如果想让这个图变成强连通图,至少添几条边.  特例是给定的图是一个强连通图的话答案是1, 0. 一般情况下我们先将这个图的强连通分量求出来缩成一个点然后统计入度为0的点和出度为0的点的个数, 答案一就是入度为0的点的个数, 答案就是他们两个之间的最大值.代码如下: /* ID: m1500293 LANG: C++ PROG: schlnet */ #include

强连通分量(学习心得)

定义:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 求强连通分量: vector<int>pic[maxn]; int dfn[maxn],low[maxn],ans[maxn]; bool ins[maxn]; stack<int>st; int dind=0,block=

POJ 2186:Popular Cows(强连通分量)

[题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, 那么我们从其中一个点开始沿反图dfs,如果能访问到全图, 则答案为其所在SCC的大小,否则为0. [代码] #include <cstdio> #include <algorithm> #include <vector> #include <cstring>

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>

【强连通分量】tarjan算法及kosaraju算法+例题

阅读前请确保自己知道强连通分量是什么,本文不做赘述. Tarjan算法 一.算法简介 Tarjan算法是一种由Robert Tarjan提出的求有向图强连通分量的时间复杂度为O(n)的算法. 首先我们要知道两个概念:时间戳(DFN),节点能追溯到的最早的栈中节点的时间戳(LOW).顾名思义,DFN就是在搜索中某一节点被遍历到的次序号(dfs_num),LOW就是某一节点在栈中能追溯到的最早的父亲节点的搜索次序号. Tarjan算法是基于深度优先搜索的算法.在搜索过程中把没有Tarjan过的点入栈