強連通分量及縮點 演算法解析及例題
演算法講解:https://blog.csdn.net/acmmmm/article/details/16361033#comments
例題:
poj-2186
http://poj.org/problem?id=2186
題意:總共有n頭牛,m個有序對(a, b) 代表牛a崇拜牛b, 崇拜具有傳遞性,求出被其他所有牛崇拜的牛的總數。
題解:構造一個圖,進行求強連通分量及縮點,在強連通分量中的奶牛肯定是被在這個強連通分量裡面奶牛所仰慕的,如果一個圖裡面有幾個強連通分量的話那麼一定至少存在一個出度為0的點,如果不存在那麼剛剛的強連通一定不是最大強連通又想如果有兩個這樣的出度為0的點存在,那麼這個圖中一定沒有滿足題意的奶牛,因為那兩個出度為0的點不會仰慕任何牛所以出度為0的點有且只能有一個!如果有多個那麼滿足題意的牛隻有0個,如果沒有的話那麼整個圖都是滿足題意的牛。
ac code:
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
#define N 10005
struct eg {
int to, next;
}ac[5*N];
int n, m, cnt, jar;
int head[N], dfn[N], low[N], instack[N], belong[N];
int nu[N];
vector<int>re[N];
stack<int>s;
void init() {
memset(nu, 0, sizeof(nu));
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
cnt = 0; jar = 0;
}
void add(int u, int v) {
ac[cnt].to = v;
ac[cnt].next = head[u];
head[u] = cnt++;
}
void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
s.push(u);
instack[u] = 1;
for (int i = head[u]; i != -1; i = ac[i].next) {
int v = ac[i].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 (low[u] == dfn[u]) {
int now;
re[jar].clear();
do {
now = s.top();
s.pop();
instack[now] = 0;
belong[now] = jar;
re[jar].push_back(now);
} while (now != u);
jar++;
}
}
int main() {
int result = 0;
int a, b;
scanf("%d%d", &n, &m);
init();
for (int i = 0; i < m; i++) {
scanf("%d%d", &a, &b);
add(a, b);
}
cnt = 0;
for (int i = 1; i <= n; i++) {
if (dfn[i] == 0)
tarjan(i);
}
for (int i = 1; i <= n; i++) {
for (int j = head[i]; j != -1; j = ac[j].next) {
int v = ac[j].to;
if (belong[i] != belong[v]) {
nu[belong[i]] = 1;
}
}
}
int ans = 0, t;
for (int i = 0; i < jar; i++) {
if (!nu[i]) {
ans++;
t = i;
}
}
if (ans > 1) {
cout << result << endl;
return 0;
}
cout << re[t].size() << endl;
return 0;
}
poj-2553
http://poj.org/problem?id=2553
求從u出發能到v,並且從v出發也能到u的這些點,並且將其輸出;求出一個圖的若干個強連通分量並且如果這個強連通分量中的縮點出度為0的話那麼這個強連通分量裡面的點就都滿足題意。
ac code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define N 5005
int n, e, cnt, ans;
int head[N], dfn[N], low[N], belong[N], nu[N], instack[N], vis[N];
vector<int>re[N];
struct eg {
int to, next;
}a[10*N];
stack<int>s;
void init() {
ans = cnt = 0;
memset(head, -1, sizeof(head));
memset(nu, 0, sizeof(nu));
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(vis, 0, sizeof(vis));
}
void add(int u, int v) {
a[cnt].to = v;
a[cnt].next = head[u];
head[u] = cnt++;
}
void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
s.push(u);
instack[u] = 1;
for (int i = head[u]; i != -1; i = a[i].next) {
int v = a[i].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 (low[u] == dfn[u]) {
int now;
re[ans].clear();
do {
now = s.top();
s.pop();
belong[now] = ans;
re[ans].push_back(now);
instack[now] = 0;
} while (now != u);
ans++;
}
}
int main() {
int x, y;
while (~scanf("%d", &n) && n != 0) {
scanf("%d", &e);
init();
for (int i = 0; i < e; i++) {
scanf("%d%d", &x, &y);
add(x, y);
}
cnt = 0;
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 != -1; j = a[j].next) {
int v = a[j].to;
if (belong[v] != belong[i]) {
nu[belong[i]] = 1;
}
}
}
for (int i = 0; i < ans; i++) {
if (!nu[i]) {
for (int j = 0; j < re[i].size(); j++) {
vis[re[i][j]] = 1;
}
}
}
int res;
for (int i = 1; i <= n; i++) {
if (vis[i]) {
res = i;
cout << i;
break;
}
}
for (int i = res + 1; i <= n; i++)
if (vis[i])
cout << " " << i;
cout << endl;
}
return 0;
}
poj-2762
http://poj.org/problem?id=2762
題意:一個有向圖中有n個點m條邊,問是否任意兩點u,v之間可以u-v或者v->u。
思路:學過強連通可以知道,在一個強連通中任意兩點都可以滿足題目條件。如果圖中有多個強連通分量,則需要在強連通分量之間建圖,再拓撲排序判斷圖中是否同時存在一個入度為零的兩點,如果存在那麼這兩點肯定不滿足題目條件。
ac code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
using namespace std;
#define N 1005
int n, m, cnt, ans, t;
int head[N], dfn[N], low[N], belong[N], nu[N], instack[N], vis[N];
vector<int>re[N];
struct eg {
int to, next;
}a[10 * N];
stack<int>s;
void init() {
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(nu, 0, sizeof(nu));
cnt = ans = 0;
}
void add(int u, int v) {
a[cnt].to = v;
a[cnt].next = head[u];
head[u] = cnt++;
}
void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
s.push(u);
instack[u] = 1;
for (int i = head[u]; i != -1; i = a[i].next) {
int v = a[i].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]) {
int now;
re[ans].clear();
do {
now = s.top();
s.pop();
re[ans].push_back(now);
instack[now] = 0;
belong[now] = ans;
} while (now != u);
ans++;
}
}
void solve() {
set<int>st[N];
vector<int>h;
int flag = 0;
for (int i = 1; i <= n; i++) {
for (int j = head[i]; j != -1; j = a[j].next) {
int v = a[j].to;
if (belong[v] != belong[i]) {
st[belong[i]].insert(belong[v]);
}
}
}
for (int i = 0; i < ans; i++) {
for (set<int>::iterator ite = st[i].begin(); ite != st[i].end(); ite++) {
//cout << i << " " << *ite << endl;
nu[*ite]++;
}
}
for (int i = 0; i < ans; i++) {
if (!nu[i]) {
h.push_back(i);
}
}
while (1) {
if (h.size() == 0)
break;
if (h.size() > 1) {
flag = 1;
cout << "No" << endl;
break;
}
int t = h[0];
h.clear();
for (set<int>::iterator ite = st[t].begin(); ite != st[t].end(); ite++) {
nu[*ite]--;
//cout << *ite << " " << nu[*ite] << endl;
if (nu[*ite] == 0)
h.push_back(*ite);
}
}
if (!flag)
cout << "Yes" << endl;
}
int main() {
int u, v;
cin >> t;
while (t--) {
scanf("%d%d", &n, &m);
init();
for (int i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
add(u, v);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
cnt = 0;
tarjan(i);
}
}
if (ans == 1) {
cout << "Yes" << endl;
}
else {
solve();
}
}
return 0;
}
相關文章
- 強連通分量及縮點tarjan演算法解析演算法
- 演算法學習之路|強連通分量+縮點演算法
- 【模板】tarjan 強連通分量縮點
- 圖之強連通、強連通圖、強連通分量 Tarjan演算法演算法
- Trajan演算法(強連通+縮點)演算法
- 強連通------tarjan演算法詳解及與縮點聯合運用演算法
- POJ 2186 Popular Cows(強連通分量縮點,Tarjan演算法)演算法
- 圖論複習之強連通分量以及縮點—Tarjan演算法圖論演算法
- HDU2767Proving Equivalences[強連通分量 縮點]UI
- 強連通分量與縮點(Tarjan演算法)(洛谷P3387)演算法
- 強連通分量(Tarjan演算法)演算法
- Tarjan演算法(強連通分量分解)演算法
- 強連通分量
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- Tarjan演算法求強連通分量總結演算法
- 強連通分量-tarjan演算法模板詳解演算法
- HDU 2767 Proving Equivalences Tarjan 強連通縮點UI
- 【演算法學習】tarjan 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- 【筆記】tarjian演算法 求強連通分量筆記演算法
- Tarjan演算法三大應用之強連通分量演算法
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- 強連通圖的演算法演算法
- Tarjan 求有向圖的強連通分量
- ZIP壓縮演算法原理分析及解壓例項程式碼演算法
- 認知網路知識點及例題總結
- ZIP壓縮演算法詳細分析及解壓例項解釋演算法
- 域名解析常見問題盤點及解答
- 強連通演算法--Tarjan個人理解+詳解演算法
- Java 下 SSL 通訊原理及例項Java
- 求有向圖的強連通分量(c語言版)C語言
- 企業郵箱的開通及解析
- WebRTC 及點對點網路通訊機制Web
- 【實驗】【索引壓縮】索引壓縮演示及優缺點總結索引
- 多域名解析及延伸知識點
- Pythonm面試題及解析2 - 重排Python面試題
- JS壓縮方法及批量壓縮JS