POJ 2186 popular cow 有向图的强联通问题 Tarjan算法
来源:互联网 发布:孕妇孕期必备软件 编辑:程序博客网 时间:2024/06/04 18:46
参考:http://hi.baidu.com/1093782566/blog/item/e5a0e9229913bd048b82a175.html
http://www.cppblog.com/IronOxide/archive/2010/08/16/123622.html?opt=admin
模型转换:N个顶点的有向图,有M条边(N≤10000,M≤50000)。求一共有多少个点,满足这样的条件:所有其它的点都可以到达这个点。
首先,这个题的N和M都非常大,硬做是肯定不行的。考虑如果这个图是一棵树,那么问题就变的很简单了,因为至多有一个点满足条件,这个点满足条件的充要条件是:这个点是树中唯一的出度为0的点。
那么我们能否把图转化为树呢?首先可以想到的是,如果图中包含有环,那么就可以把这个环缩成一个点,因为环中的任意两个点可以到达,环中所有的点具有相同的性质,即它们分别能到达的点集都是相同的,能够到达它们的点集也是相同的。缩点后的图必无环,否则,可将环上所有点也缩成一个点,与极大强联通分量矛盾。
那么是否只有环中的点才具有相同的性质呢?进一步的考虑,图中的每一个极大强连通分支中的点都具有相同的性质。所以,如果把图中的所有极大强连通分支求出后,就可以把图收缩成一棵树,问题就迎刃而解了。
预备知识:有向图的强连通分量的求法,这个和求割点的算法差不多。算法框架:对有向图求强连通分量,然后找出所有独立的强连通分量(所谓独立,就是该连通分量里面的点到外面的点没有通路,当然,连通分量外的点是可以有路到强连通分量内的点的),如果独立的强连通分量的数目只有一个,那么,就输出这个强连通分量内解的个数,否则输出无解。只要找到缩点后的图中无出度的点的个数,设为cnt, 若 cnt > 1 , 则必无满足条件的点,因为一个出度为
零的点无法到达另一个出度为零的点;若cnt = 1 , 则该点所对应的强联通分量的点的个数即为答案。
算法证明:
1:假设a和b都是最受欢迎的cow,那么,a欢迎b,而且b欢迎a,于是,a和b是属于同一个连通分量内的点,所有,问题的解集构成一个强连通分量。
2:如果某个强连通分量内的点a到强连通分量外的点b有通路,因为b和a不是同一个强连通分量内的点,所以b到a一定没有通路,那么a不被b欢迎,于是a所在的连通分量一定不是解集的那个连通分量。
3:如果存在两个独立的强连通分量a和b,那么a内的点和b内的点一定不能互相到达,那么,无论是a还是b都不是解集的那个连通分量,问题保证无解。
4:如果图非连通,那么,至少存在两个独立的连通分量,问题一定无解。
- #include <iostream>
- #include <stack>
- #include <cstring>
- using namespace std;
- const int MAXN = 10000 + 10; // 点的最大数量
- const int MAXM = 50000 + 10; // 边的最大数量
- // 假设对边u-->v
- struct EDGE
- {
- int v; // 从u点出发能到达的点v
- int next; // 从u点出发能到达的下一条边的编号
- };
- stack<int> s;
- EDGE edge[MAXM];
- int low[MAXN]; // low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号
- int dfn[MAXN]; // dfn[u]:节点u搜索的次序编号(时间戳)
- int first[MAXN]; // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)
- int sccf[MAXN]; // sccf[i] = j:第i个点所在的强连通分量的编号
- bool ins[MAXN]; // 是否在栈中
- int outdegree[MAXN]; // 强连通分量的出度
- int index; // 次序编号
- int scc; // 强连通分量的数目
- int n, m;
- void Init()
- {
- scc = 0;
- index = 1;
- memset(low, 0, sizeof(low));
- memset(dfn, 0, sizeof(dfn));
- memset(ins, false, sizeof(ins));
- memset(sccf, 0, sizeof(sccf));
- memset(first, -1, sizeof(first));
- }
- void Tarjan(int u)
- {
- int v;
- low[u] = dfn[u] = index++;
- s.push(u);
- ins[u] = true;
- // 枚举每一条边:u-->v
- for (int k=first[u]; k!=-1; k=edge[k].next)
- {
- v = edge[k].v;
- if (dfn[v] == 0)
- {
- Tarjan(v);
- low[u]=min(low[u],low[v]);
- }
- else if (ins[v])
- {
- low[u]=min(low[u],dfn[v]);
- }
- }
- // 如果节点u是强连通分量的根
- if (dfn[u] == low[u])
- {
- scc++;
- do
- {
- v = s.top();
- s.pop();
- ins[v] = false;
- sccf[v] = scc;
- }while (u != v);
- }
- }
- // 获得超级受喜欢的cows的数量
- int GetSuperPopularNum()
- {
- int u, v;
- int cnt = 0; // 出度为0的强连通分量的数目
- int ct[MAXN]; // ct[i] = j:强连通分量i有j个点
- memset(outdegree, 0, sizeof(outdegree));
- memset(ct, 0, sizeof(ct));
- // 枚举每一个点u:求outdegree和ct
- for (u=1; u<=n; u++)
- {
- ct[sccf[u]]++;
- for (int k=first[u]; k!=-1; k=edge[k].next)
- {
- // 对每条边u-->v
- v = edge[k].v;
- if (sccf[u] != sccf[v])
- {
- outdegree[sccf[u]]++;
- }
- }
- }
- // 数数强连通分量为0的点有多少个
- for (u=1; u<=scc; u++)
- {
- if (outdegree[u] == 0)
- {
- cnt++;
- v = u;
- }
- }
- return (cnt == 1)? ct[v] : 0;
- }
- int main()
- {
- int i, u, v;
- int e = 0; // 边的数量,建图时会用到
- // 初始化数据并建图
- Init();
- cin >> n >> m;
- for (i=0; i<m; i++)
- {
- cin >> u >> v;
- edge[e].v = v;
- edge[e].next = first[u];
- first[u] = e;
- e++;
- }
- // 求强连通分量
- for (i=1; i<=n; i++)
- {
- if (dfn[i] == 0)
- {
- Tarjan(i);
- }
- }
- // 输出答案
- cout << GetSuperPopularNum() << endl;
- return 0;
- }
0 0
- POJ 2186 popular cow 有向图的强联通问题 Tarjan算法
- POJ 2186 popular cow 有向图的强联通问题 Tarjan算法
- poj 2186 Popular Cows (有向图的联通分量问题)
- poj 2186 Popular Cows 有向图强连通分量 tarjan
- 求有向图强联通分量--Tarjan算法
- 求解有向图的强连通分量的SCC问题---POJ 2186 Popular Cows
- 有向图的强联通tarjan算法(判断是否为强联通模板)(hdu1269)
- poj 2186 Popular Cows 强联通分量tarjan/Kosaraju
- POJ 2186 Popular Cows(强联通分量缩点+tarjan算法)
- 有向图的强联通分量 tarjan
- bzoj1654[The Cow Prom 奶牛舞会] tarjan求有向无环图的强联通分量
- 有向图的强联通分量Tarjan算法模版(hdu1269)
- 求解有向图的强联通分量--tarjan算法(tarjian求最小环模板)
- POJ 2186(有向图的强连通分量Tarjan)
- 有向图强连通分量-poj-2186-Popular Cows
- 链式前向星,kosaraju,Tarjan,Gabow算法的理解,POJ 2186 Popular Cows(强连通分量)
- Popular Cows+求强联通量简单题+tarjan算法+POJ
- POJ 2186 Popular Cows(强连通分量Tarjan算法)
- The Semantics of Function
- Targan 算法[有向图强连通分量]
- 布局的复用
- CentOS yum安装mysql后 Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’
- 大数据处理
- POJ 2186 popular cow 有向图的强联通问题 Tarjan算法
- 远程快速杀死session!
- Find The Multiple poj1426
- [漏洞分析] Wolf CMS 0.8.2中任意文件上传漏洞
- 在Windows7中装Ubuntu双系统
- mysql 安装mysqlbackup
- 机器学习和人工智能将开创计算机2.0时代
- C语言 用递归法将一个整数n转换成字符串
- 数据库第五章作业