生活随笔
收集整理的這篇文章主要介紹了
受欢迎的牛(有向图的强连通分量)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目:https://www.acwing.com/problem/content/1176/
tarjan:O(n+m),,,這個tarjan算法,除了求強連通分量(合并完的環),還可以順便求圖中所有的環的數量(不是合并完的環),自己測的,沒有證明,代碼中的sss就是。
題意:如果A–》B,B–》C,那么A–》C,問在這個有向圖中有多少個這樣的A,除了A個點外的所有點都能有路走到A。
題解:暴力做法,就是枚舉每一個點,看一下其他所有點是否都能到這個點,這個時間復雜度是n方級別的,肯定不行。
如果這個圖有拓撲序列的話,那么按照這個拓撲序列走一遍,看看有一個出度為0的點,如果有一個出度為0的點,那么其它所有點就一定能走到這個點,但是這個圖可能有環,所以它不一定有拓撲序列。
但是又可以發現,在這個題中,一個環中所有點是任意到達的,所以如果其它所有點都能到這個環,那么這個環中的所有點都是題目中要求的點,而且在這個環中,如果其中一個點可以走到環外的一個點,那么環中其它所有點也可以走到那個點,所以就可以把一個環看成一個點,把所有的環都壓縮成一個點,那么就可以這個圖就有拓撲序列了(當然,可能有環套環(最外層有個大環,里面的一些點又有一些小環)、環連環(倆個環通過都包括一個點)的情況,會把這些環一起都壓縮成一個點),這樣就可以做這個題了,而求一個圖中的環的數量(這里的環的意義是環連環、環套環算是一個環,其實就是強連通分量),即求強連通分量的數量,用tarjan做法。
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define pb push_back
#define pii pair<int, int>
#define mpr make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
#define x first
#define y second
typedef long long ll
;
const int inf
= 0x3f3f3f3f;
const ll INF
= 0x3f3f3f3f3f3f3f3f;
using namespace std
;
inline int read() {char ch
= getchar();int s
= 0, w
= 1;while (ch
< '0' || ch
> '9') {if (ch
== '-') w
= -1;ch
= getchar();}while (ch
>= '0' && ch
<= '9') {s
= s
* 10 + ch
- '0', ch
= getchar();}return s
* w
;
}
const int N
= 10010, M
= 50010;
int n
, m
;
int h
[N
], e
[M
], ne
[M
], idx
;
int dfn
[N
], low
[N
], timestamp
;
int stk
[N
], top
;
bool in_stk
[N
];
int id
[N
], scc_cnt
, id_size
[N
];
int dout
[N
];
void add(int a
, int b
) { e
[idx
] = b
, ne
[idx
] = h
[a
], h
[a
] = idx
++; }
void tarjan(int u
) {dfn
[u
] = low
[u
] = ++timestamp
;stk
[++top
] = u
, in_stk
[u
] = true;for (int i
= h
[u
]; i
!= -1; i
= ne
[i
]) { int j
= e
[i
];if (!dfn
[j
]) { tarjan(j
);low
[u
] = min(low
[u
], low
[j
]); } else if (in_stk
[j
]) low
[u
] = min(low
[u
], low
[j
]);}if (dfn
[u
] == low
[u
]) {int y
;++scc_cnt
;do {y
= stk
[top
--];in_stk
[y
] = false;id
[y
] = scc_cnt
;id_size
[scc_cnt
]++;} while (y
!= u
);}
}
signed main() {scanf("%d%d", &n
, &m
);memset(h
, -1, sizeof(h
));while (m
--) {int a
, b
;scanf("%d%d", &a
, &b
);add(a
, b
);}for (int i
= 1; i
<= n
; i
++) {if (!dfn
[i
]) tarjan(i
); }for (int i
= 1; i
<= n
; i
++) {for (int j
= h
[i
]; ~j
; j
= ne
[j
]) {int k
= e
[j
];int a
= id
[i
], b
= id
[k
];if (a
!= b
) dout
[a
]++;}}int zeros
= 0, sum
= 0; for (int i
= 1; i
<= scc_cnt
; i
++) {if (!dout
[i
]) {zeros
++; sum
+= id_size
[i
];if (zeros
> 1) {sum
=0;break;}}}printf("%d\n", sum
);return 0;
}
總結
以上是生活随笔為你收集整理的受欢迎的牛(有向图的强连通分量)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。