算法学习—— tarjan算法求强连通分量 (附带 hdu1827
2016-11-18 23:55
281 查看
tarjan算法的第三个应用 求强连通分量
强连通分量我就不具体介绍了
这次的关键数组含义仍然没变 low[u] 仍然还是 u 能到达的最小的 low[v] ( low[v] 又由它最小的 low[v'] 决定
这里有个很关键的点 low[u] == dfn[u] 若以 求割点与桥的tarjan理解 表示 u 的子树的结点中最早能返回到 u,不能访问到u的祖先, 而 u 又必然能访问到 其子树,因此很简容易便能理解 u 及其子树形成了一个最大的连通块 即 强连通分量
而根据 dfs 的 递归与回溯特性 我们以一个栈来存储一个强连通分量 当得到 low[u]==dfn[u] 时可以逐个出栈得到强连通中的所有结点
鉴于强连通的特性 我们可以将算法简单优化一下 比如 不在 连通栈中的结点 我们已经无需去更新它的 low[u]
hdu 1827
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3360 Accepted Submission(s): 1525
Problem Description
To see a World in a Grain of Sand
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
—— William Blake
听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
Input
多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output
输出最小联系人数和最小花费。
每个CASE输出答案一行。
Sample Input
12 16
2 2 2 2 2 2 2 2 2 2 2 2
1 3
3 2
2 1
3 4
2 4
3 5
5 4
4 6
6 4
7 4
7 12
7 8
8 7
8 9
10 9
11 10
Sample Output
3 6
ac code
这题的话 tarjan算法求一下缩点 并且吧强连通分量中最小的值记录下来 最后计算下入度为0 的点 加上即可(一开始我还想用并查集 还是太嫩了…………
这个算法最大的应用便是求 缩点 这真是解决了我一直以来的大问题!!!!
感觉今天真是刷到了一把神器!!!
强连通分量我就不具体介绍了
这次的关键数组含义仍然没变 low[u] 仍然还是 u 能到达的最小的 low[v] ( low[v] 又由它最小的 low[v'] 决定
这里有个很关键的点 low[u] == dfn[u] 若以 求割点与桥的tarjan理解 表示 u 的子树的结点中最早能返回到 u,不能访问到u的祖先, 而 u 又必然能访问到 其子树,因此很简容易便能理解 u 及其子树形成了一个最大的连通块 即 强连通分量
而根据 dfs 的 递归与回溯特性 我们以一个栈来存储一个强连通分量 当得到 low[u]==dfn[u] 时可以逐个出栈得到强连通中的所有结点
鉴于强连通的特性 我们可以将算法简单优化一下 比如 不在 连通栈中的结点 我们已经无需去更新它的 low[u]
hdu 1827
Summer Holiday
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3360 Accepted Submission(s): 1525
Problem Description
To see a World in a Grain of Sand
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
—— William Blake
听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
Input
多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output
输出最小联系人数和最小花费。
每个CASE输出答案一行。
Sample Input
12 16
2 2 2 2 2 2 2 2 2 2 2 2
1 3
3 2
2 1
3 4
2 4
3 5
5 4
4 6
6 4
7 4
7 12
7 8
8 7
8 9
10 9
11 10
Sample Output
3 6
ac code
这题的话 tarjan算法求一下缩点 并且吧强连通分量中最小的值记录下来 最后计算下入度为0 的点 加上即可(一开始我还想用并查集 还是太嫩了…………
/* *********************************************************************** > File Name: contest.cpp > Author: Key > Mail: keyld777@gmail.com > Created Time: 2016年11月18日 星期日 20时10分38秒 ********************************************************************** */ #include <algorithm> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1005; int n, m, indx, vis_time, ansn, scn, top; int head[maxn], low[maxn], dfn[maxn], stack[maxn], val[maxn], color[maxn], minval[maxn]; int in[maxn]; bool instack[maxn]; struct node { int from; int to; int next; // int w; }; node edge[2 * maxn]; void AddEdge(int u, int v) { edge[indx].from = u; edge[indx].to = v; edge[indx].next = head[u]; head[u] = indx++; } void init() { vis_time = indx = ansn = scn = top = 0; memset(head, -1, sizeof head); memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(in,0,sizeof in); } void tarjan(int u) { int v; low[u] = dfn[u] = ++vis_time; instack[u] = true; stack[++top] = u; for (int id = head[u]; id != -1; id = edge[id].next) { v = edge[id].to; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v]) low[u] = min(low[u], dfn[v]); } if (dfn[u] == low[u]) { scn++; minval[scn]=val[u]; do { v = stack[top--]; instack[v] = false; color[v] = scn; minval[scn]=min(minval[scn],val[v]); } while (v != u); } } int main() { int u, v; while (scanf("%d %d", &n, &m) != EOF) { init(); for (int i = 1; i <= n; i++) scanf("%d", val + i); for (int i = 0; i < m; i++) { scanf("%d %d", &u, &v); AddEdge(u, v); } for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (int i = 0; i < m; i++) { u = edge[i].from; v = edge[i].to; if (color[u] != color[v]) in[color[v]]++; } int ans=0,ansn=0; for(int i=1;i<=scn;i++) if(in[i]==0){ ansn++; ans+=minval[i]; } printf("%d %d\n",ansn,ans); } return 0; }
这个算法最大的应用便是求 缩点 这真是解决了我一直以来的大问题!!!!
感觉今天真是刷到了一把神器!!!
相关文章推荐
- |算法讨论|强连通分量Tarjan 学习笔记
- POJ 2186 Popular Cows(Tarjan算法求强连通分量)
- 【算法学习】强连通分量
- tarjan 算法求强连通分量
- 图论——强连通分量:Tarjan算法——练习1
- hdu 1269 迷宫城堡 tarjan算法求有向图的强连通分量
- 图论 tarjan 有向图 的 强连通分量(noip算法每周过)
- Hdu 2586 学习 LCA 的 Tarjan 算法
- Tarjan算法求解强连通分量(SCC)
- 算法模板——Tarjan强连通分量
- 强连通分量(强连通缩点(tarjan))+最小路径覆盖(匈牙利算法)
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- 刻录光盘(Tarjan算法求强连通分量)
- hdu 4685 Prince and Princess 【匈牙利算法-匹配、强连通分量-Tarjan-缩点】
- 图论算法(6)(更新版) --- Tarjan算法求强连通分量
- hdu1827 强连通分量tarjan(初战)
- 强连通分量及缩点tarjan算法解析
- tarjan 算法(求强连通分量)
- 【算法及其原理】 Tarjan——求有向图中的强连通分量
- Tarjan算法求强连通分量