poj 2186 "Popular Cows"(强连通分量入门题)
参考资料:
[1]:挑战程序设计竞赛
题意:
每头牛都想成为牛群中的红人。
给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人;
该关系具有传递性,所以如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人。
不过,给定的有序对中可能包含(A, B)和(B, C),但不包含(A, C)。
求被其他所有牛认为是红人的牛的总数。
分析(摘抄自挑战程序设计竞赛):
考虑以牛为顶点的有向图,对每个有序对(A, B)连一条从 A到B的有向边;
那么,被其他所有牛认为是红人的牛对应的顶点,也就是从其他所有顶点都可达的顶点。
虽然这可以通过从每个顶点出发搜索求得,但总的复杂度却是O(NM),是不可行的,必须要考虑更为高效的算法。
假设有两头牛A和B都被其他所有牛认为是红人,那么显然,A被B认为是红人,B也被A认为是红人;
即存在一个包含A、B两个顶点的圈,或者说,A、B同属于一个强连通分量。
反之,如果一头牛被其他所有牛认为是红人,那么其所属的强连通分量内的所有牛都被其他所有牛认为是红人。
由此,我们把图进行强连通分量分解后,至多有一个强连通分量满足题目的条件。
而按前面介绍的算法进行强连通分量分解时,我们还能够得到各个强连通分量拓扑排序后的顺序;
唯一可能成为解的只有拓扑序最后的强连通分量。
所以在最后,我们只要检查这个强连通分量是否从所有顶点可达就好了。
该算法的复杂度为O(N+M),足以在时限内解决原题。
对红色字体的理解:
满足条件的强连通分量的特点是(红牛所在的强连通分量):
(1)出度为0
(2)其余的节点都会间接或直接的指向此强连通分量的任一节点
再结合向量vs 的作用,在Dfs( )中,vs中存储的第一个节点肯定是满足条件的强连通分量中的某一节点;
在vs中,越靠前的节点的拓扑序越大。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e5+; int n,m;
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[*maxn];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
struct SCC
{
int col[maxn];
bool vis[maxn];
vector<int >vs;
void DFS(int u)
{
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if((i&) || vis[v])//正向边,num为偶数
continue;
DFS(v);
}
vs.push_back(u);
}
void RDFS(int u,int k)
{
vis[u]=true;
col[u]=k;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(!(i&) || vis[v])//反向边,num为奇数
continue;
RDFS(v,k);
}
}
int scc()
{
vs.clear();
mem(vis,false);
for(int i=;i <= n;++i)
if(!vis[i])
DFS(i); int k=;
mem(vis,false);
for(int i=vs.size()-;i >= ;--i)//从拓扑序的最大值开始查找SCC
if(!vis[vs[i]])
RDFS(vs[i],++k);
return k;
}
}_scc;
int Solve()
{
int k=_scc.scc();
int ans=;
int u;
for(int i=;i <= n;++i)
if(_scc.col[i] == k)
{
ans++;
u=i;
}
mem(_scc.vis,false);
_scc.RDFS(u,);//再次调用RDFS()判断u是否可以到达其他任意节点
for(int i=;i <= n;++i)
if(!_scc.vis[i])
return ;
return ans;
}
void Init()
{
num=;
mem(head,-);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
Init();
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
printf("%d\n",Solve());
}
return ;
}
poj 2186 "Popular Cows"(强连通分量入门题)的更多相关文章
- poj 2186 Popular Cows (强连通分量+缩点)
http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissi ...
- POJ 2186 Popular Cows 强连通分量模板
题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #in ...
- POJ 2186 Popular Cows --强连通分量
题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样, ...
- POJ 2186 Popular Cows(强连通分量缩点)
题目链接:http://poj.org/problem?id=2186 题目意思大概是:给定N(N<=10000)个点和M(M<=50000)条有向边,求有多少个“受欢迎的点”.所谓的“受 ...
- poj 2186: Popular Cows(tarjan基础题)
题目链接 tarjan参考博客 题意:求在图上可以被所有点到达的点的数量. 首先通过tarjan缩点,将所有内部两两可达的子图缩为一点,新图即为一个有向无环图(即DAG). 在这个DAG上,若存在不止 ...
- 强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)
poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且能够传递, 即1欢迎2不代表2欢迎1, 可是假设2也欢迎3那么1也欢迎3. 求 ...
- poj 2186 Popular Cows 【强连通分量Tarjan算法 + 树问题】
题目地址:http://poj.org/problem?id=2186 Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Sub ...
- POJ 2186 Popular Cows (强联通)
id=2186">http://poj.org/problem? id=2186 Popular Cows Time Limit: 2000MS Memory Limit: 655 ...
- tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows
缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...
随机推荐
- vue 动态修改 css
<div v-for="i in resultDate" v-if="i.ProjectId>='4'" @click=EveyTesttInfo( ...
- 个人git链接和git学习心得总结
个人git链接和git学习心得总结 个人git链接: https://github.com/hanzhaoyan Git 是 Linux 的创始人 Linus Torvalds 开发的开源和免费的版本 ...
- Oracle系列(二): Oracle表的外键查询
在执行数据库删除操作时,外键关联是令我们最烦的一个东西,有了外键关联,就不允许随意删除数据,那么怎知道这个外键关联度的外键属于那个表? select * from user_cons_columns ...
- C#获取当月第一天和最后一天
当月第一天0时0分0秒: DateTime.Now.AddDays(1 - DateTime.Now.Day).Date 当月最后一天23时59分59秒: DateTime.Now.AddDays(1 ...
- h5定位geolaction无法调试解决方法
昨天接到一个在h5获取经纬度的需求,看了文档后,代码其实很简单,但在浏览器上调试就比较蛋疼了... 代码: function successfulCallback(position) { consol ...
- ABP编译必须添加对程序集“netstandard, Version=2.0.0.0错误
当前使用ABP版本为:4.6.0 升级vs2017到15.4版本,升级framework到4.7版本 如果Core版本请升级到net core 2
- PAT L2-012 关于堆的判断
https://pintia.cn/problem-sets/994805046380707840/problems/994805064676261888 将一系列给定数字顺序插入一个初始为空的小顶堆 ...
- Java与JavaScript之间关于JSON的是非恩怨
http://blog.csdn.net/joyhen/article/details/43271569 js 单引号替换成双引号,双引号替换成单引号 操作 解决问题的场景: Java端生成了JSON ...
- Cron Expression的用途
对于一些MIS系统,DeadLine,需要用户自己制定事件规则,Cron Expression应该可以派上用场. Cron Maker: http://www.cronmaker.com/
- [日常工作]Win2008r2 以及更高版本的操作系统安装Oracle10.2.0.5
1. 当时有特殊需求, 客户有win2008r2sp1以上的windows系统,但是数据库要使用Oracle10.2.0.5 的版本. 问题: 1. Oracle10 最高支持到 Win2008sp2 ...