洛谷P2341 强连通分量
题面
每一个奶牛都喜欢自己,除此以外还有一些喜欢的对象,用边表示。
并且奶牛的喜欢符合传递关系,即A喜欢B,B喜欢C则A喜欢C
被全体奶牛喜欢的奶牛称为明星
给出N头奶牛和M个喜欢关系,求明星数量
1<=N<=10000,1<=M<=50000
分析
如果整个图只是一个强连通分量,那么显然所有点间都可相互到达(喜欢都能传递到),所以图内所有点都是明星。
考虑有多个强连通分量的情况,可以把每个强连通分量先缩点。
像这种情况,因为有F→C的边,所以分量2中的点都能到达分量1,分量1的出度为0,也就可以做到让分量1内的ABC成为明星
而如果删去F→C的边,分量1和2的出度都为0,就不可能做到某个牛成为明星,因为另一个分量的牛都不喜欢它
经过思考,最终的情况其实就是:当存在大于等于2个分量出度为0时,就不存在明星(如两个出度0的分量中取一个牛,另一个分量中的牛都不喜欢它,不满足所有牛都喜欢)
1个分量出度为0时,其余分量的喜欢可以传递给它,所以这个分量内所有牛都是明星
0个分量出度0,空图。。。就不存在了。
这是求完强连通分量之后的缩点问题,关于求强连通分量,我用的是tarjan的板子。
tarjan法求强连通分量的算法其实和求割点差不多,都用到了pre,low函数,一样的dfs。
标记分量的方法就是找到dfs中第一个进入某个分量的元素,这个元素的特点是low[u]=pre[u],在dfs过程中用一个栈存下还没有分配连通块的元素,一旦遇到了low[u]=pre[u],就连续出栈到u,这一次出栈的元素都属于同一个强连通分量。
代码
#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
vector<int> G[50004];
int dfs_clock = 0, scc_cnt = 0;//时间戳,强连通分量组编号
int sccno[10004];//表示每个点属于哪个强连通块
int pre[10004];//dfs序
int low[10004];//low[u]表示u及其后带通过反向边最多能返回到哪
stack<int> s;//存当前的节点
int out[10004];//出度统计,序号是强连通分量的编号
void dfs(int u)
{pre[u] = low[u] = ++dfs_clock;s.push(u);for (int i = 0; i < G[u].size(); i++){int v = G[u][i];//下一个if (!pre[v])//未到过v{dfs(v);low[u] = min(low[u], low[v]);}else if (!sccno[v])//有可能是新的反向边{low[u] = min(low[u], pre[v]);}}if (low[u] == pre[u])//是第一次发现这个连通分量的点{scc_cnt++;while (true){int x = s.top();s.pop();sccno[x] = scc_cnt;if (x == u)break;}}
}
void find_scc(int n)
{for (int i = 1; i <= n; i++){if (!pre[i])dfs(i);}
}
int main()
{ios::sync_with_stdio(false);int n, m,u,v;cin >> n >> m;for (int i = 0; i < m; i++){cin >> u >> v;G[u].push_back(v);}find_scc(n);//开始寻找强连通分量的函数//sccno已经处理完,1~scc_cnt//开始处理每个块的出度问题for (int i = 1; i <= n; i++){for (int j = 0;j < G[i].size();j++)//(i,G[i][j])是一条边{if (sccno[i] != sccno[G[i][j]])out[sccno[i]]++;//不是同一个块,则i的出度++}}int ans = 0;//此时记录out为0的块的个数for (int i = 1; i <= scc_cnt; i++){if (out[i] == 0)ans++;}if (ans > 1)cout << 0;//有2个及以上出度0的块,不存在明星else {ans = 0;for (int i = 1; i <= n; i++){if (out[sccno[i]] == 0)ans++;//输出出度0的块内所有点}cout << ans;}return 0;
}
求强连通分量部分参考了《算法竞赛入门经典-训练指南》的板子
洛谷P2341 强连通分量相关推荐
- 上白泽慧 洛谷1726 强连通分量
题目描述 在幻想乡,上白泽慧音是以知识渊博闻名的老师.春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄.因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点.人间 ...
- 洛谷P2341 [HAOI2006]受欢迎的牛 (Tarjan,SCC缩点)
P2341 [HAOI2006]受欢迎的牛|[模板]强连通分量 https://www.luogu.org/problem/P2341 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就 ...
- 洛谷 P2341 - 受欢迎的牛
题目描述 P2341 [USACO03FALL][HAOI2006]受欢迎的牛 G 解法: 首先,明确一下什么是明星奶牛:受欢迎的牛只可能是图中唯一的出度为0的强连通分量中的所有奶牛. 为什么? 强连 ...
- 洛谷 P2341 [HAOI2006]受欢迎的牛
题目 题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的"喜欢" ...
- 洛谷P2341(Tarjan+缩点)
解题报告:对于Tarjan的之前的理解的更正: 关于low数组在同一个联通分量中并不是所有的点都是标记为该搜索树的dfn!所以用book数组充当染色的角色. 关于该题的大意就是如果存在两个或以上的明星 ...
- 洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows
P2341 [HAOI2006]受欢迎的牛/POJ2186:Popular Cows 题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所 ...
- 洛谷 P2341 【HAOI2006】受欢迎的牛
题目链接 https://www.luogu.org/problem/P2341 分析 Tarjan缩点,最后DAG中,唯一的出度为 000 的点的大小即为答案. AC代码 #include < ...
- 洛谷P2341 受欢迎的牛
题目链接:https://www.luogu.org/problem/show?pid=2341 解题思路: 1.首先可以想到在一个联通块内的牛都可以成为明星奶牛(互相喜欢).这样我们就可以把它们缩成 ...
- 洛谷P2341(受欢迎的牛)题解
题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的"喜欢"是可以传递的--如果A喜 欢B,B喜 ...
最新文章
- 《Attention is All You Need》浅读(简介+代码)
- 不计前嫌,握手言和:Microsoft宣布新版SQL Server将同时支持Windows与Linux两大平台...
- c++(和opencv)如何把局部变量变成全局变量的功能
- git错误fatal: remote origin already exists.
- 多個excel文件合并到一個excel文件
- 使用Google Guava创建收藏和实现不变性
- Unity3d LookAt参数说明
- Delphi 的绘图功能[9] - TextRect
- Unit5 Survival Shooter笔记3
- 清明,我怀念那个回不去的故乡了
- 关于strcpy的安全函数的选择
- java简历模板来了!!
- mysql busy buffer_与buffer cache相关的等待事件—buffer busy waits等待事件!
- 数商云化妆品行业电商平台系统解决方案
- Linux的vx开头的文件,微博 Qzone 微信 Linux文件及目录常用命令,进来瞅瞅
- 绿色软件在Windows10中设置开机自启方法
- 漫画安全HIDS、EDR、NDR、XDR
- web打印模板神器reportbro
- 百度计算机调试员论文,基于西门子工业软件的仿真专业系统设计一阶惯性加纯滞后对象百度精.doc...
- HIN 异构信息网络(Heterogeneous Information Network)