[SMOJ1419]受欢迎的奶牛
来源:互联网 发布:股市行情数据 编辑:程序博客网 时间:2024/05/15 09:10
等我搬这题笔记的时候,lgj 已经把 smoj 上对应的题封了,所以抱歉,只能搬原题(poj2186)过来,不便之处敬请原谅。
Description
Every cow’s dream is to become the most popular cow in the herd. In a herd of
N (1≤N≤10,000 ) cows, you are given up toM (1≤M≤50,000 ) ordered pairs of the form(A,B) that tell you that cowA thinks that cowB is popular. Since popularity is transitive, ifA thinksB is popular andB thinksC is popular, thenA will also think thatC is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
Line 1: Two space-separated integers,
N andM
Lines 2..1+M : Two space-separated numbersA andB , meaning thatA thinksB is popular.
Output
Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
Source
USACO 2003 Fall
很显然有若干个结点(奶牛),若干条边(认为受欢迎的关系),要找某种特定点的个数。这应该是一个图论的问题。
再来作进一步的分析。如果奶牛
什么情况下,其他结点可以到达自己呢?我们知道,在有向图的强连通分量中,任意两个结点之间互相可达。而将原图缩点后,就变成了一个 DAG 。既然无环,在新图中,出度为 0 的强连通分量,就可能是所求的答案。如下图的样例,缩点后 1 和 2 成为了一个强连通分量,出度为 1,3的出度为 0。因此 3 就是我们要求的点。
做法:Tarjan缩点,顺便记录新图中各个结点包含了原图中多少个结点,再判断新图中出度为0的新结点是否只有1个,如果是,则输出该新结点包含了原图中多少个结点。
证明:首先,在新图中,必然存在出度为 0 的结点,否则就会存在环,不是极大连通子图。(画几个例子就可以推导得出,有兴趣可以自行作严谨的证明)
其次,如果出度为 0 的新结点多于 1 个,由 DAG 的性质显然它们之间互相不可达,于是它们都不满足“其他任何结点都要可以到达它”的要求。
综上所述,原问题存在答案,当且仅当原图缩点后有 1 个出度为 0 的新结点,而该新结点所包含的原图结点个数就是所求答案;否则原问题的解为 0。
参考代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <stack>#include <vector>using namespace std;const int maxn = 1e4 + 100;const int maxm = 5e4 + 100;struct Edge { int to, next;} edge[maxm];int cntEdge = 0;int n, m;int head[maxn];void addEdge(int u, int v) { edge[++cntEdge].to = v; edge[cntEdge].next = head[u]; head[u] = cntEdge;}int timeStamp = 0;int dfn[maxn], low[maxn];bool inStack[maxn];stack <int> st;int cntScc = 0;int belong[maxn];int num[maxn];void tarjan(int root) { dfn[root] = low[root] = ++timeStamp; inStack[root] = true; st.push(root); for (int i = head[root]; i; i = edge[i].next) { int j = edge[i].to; if (!dfn[j]) { tarjan(j); low[root] = min(low[root], low[j]); } else if (inStack[j]) low[root] = min(low[root], dfn[j]); } if (dfn[root] == low[root]) { ++cntScc; int i; do { i = st.top(); st.pop(); inStack[i] = false; belong[i] = cntScc; ++num[cntScc]; } while (i != root); }}int outDegree[maxn]; //统计强连通分量的出度int main(void) { freopen("1419.in", "r", stdin); freopen("1419.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); addEdge(a, b); } memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(inStack, false, sizeof inStack); for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); //缩点 for (int i = 1; i <= n; i++) for (int j = head[i]; j; j = edge[j].next) if (belong[i] != belong[edge[j].to]) outDegree[belong[i]]++; int cnt = 0; int ans; for (int i = 1; i <= cntScc; i++) if (!outDegree[i]) { cnt++; ans = num[i]; } if (cnt == 1) printf("%d\n", ans); else puts("0"); return 0;}
- [SMOJ1419]受欢迎的奶牛
- poj-2186 受欢迎的奶牛(tarjan算法应用)
- usaco 月赛 2003 Fall Popular Cows 受欢迎的奶牛 题解
- 由 USACO2003 Popular Cows[受欢迎的奶牛] 认识 Tarjan 求强连通分量并缩点
- 买头能下崽的奶牛
- 奶牛的锻炼
- 奶牛的午餐
- 坚强的奶牛噢
- USACO 奶牛的锻炼
- 奶牛的锻炼
- Codevs4246 奶牛的身高
- 奶牛的狂欢节
- 奶牛的锻炼
- 奶牛的锻炼...dp
- 奶牛的锻炼
- 奶牛的比赛(contest)
- 奶牛的锻炼
- LINUX的“脏奶牛”
- 非常好的理解遗传算法的例子
- BIRT报表
- 在java中通过WritableWorkbook实现Excel导出
- 欢迎使用CSDN-markdown编辑器
- Gson使用指南(4)
- [SMOJ1419]受欢迎的奶牛
- Mac os 文件复制
- Android多线程的四种方式
- Shiro缓存整合EhCache
- 让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法
- 救急,非IE浏览器实现Javascript对文件上传与下载操作
- Android截屏总结
- 使用ffmpeg合并2路视频
- 大数据与深度学习有什么区别?