求桥+割点+连通块+map重边:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 1e4 + 10;
const int MAXM = 2e5 + 10;
int head[MAXM], low[MAXM], dfn[MAXM];
int add_block[MAXM], stack[MAXM];
bool cut[MAXM], instack[MAXM];
int cnt, index_, top, bridge;
map<int, int> ma;
struct Edge {
int to;
int next;
bool cut_;
}edge[MAXM];
void addedge(int u, int v) {
edge[cnt].to = v;
edge[cnt].next = head[u];
edge[cnt].cut_ = false;
head[u] = cnt++;
}
void tarjan(int u, int fa) { //tarjan找割点,桥
int v;
low[u] = dfn[u] = ++index_;
stack[top++] = u;
instack[u] = true;
int son = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
v = edge[i].to;
if(v == fa) continue;
if(!dfn[v]) {
son++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u] && ma[u * MAXN + v] == 1) { //求桥(判重边)
bridge++; //桥的数量
edge[i].cut_ = true; //该边是桥
edge[i^1].cut_ = true;
}
if(u != fa && low[v] >= dfn[u]) {
cut[u] = true; //该点是割点
add_block[u]++; //割该点之后,连通块的数量
}
}
else {
low[u] = min(dfn[v], low[u]);
}
}
if(u == fa && son > 1) cut[u] = true; //该点是割点
if(u == fa) add_block[u] = son - 1; //割该点之后,连通块的数量
instack[u] = false;
top--;
}
void init() { //初始化
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(cut, 0, sizeof(cut));
cnt = index_ = top = bridge = 0;
ma.clear();
}
void solve(int n) {
for(int i = 1; i <= n; ++i) {
if(!dfn[i]) {
tarjan(i, i);
}
}
//加输出
}
int main() {
int n, m, T;
scanf("%d", &T);
while(T--) {
init();
scanf("%d %d", &n, &m);
while(m--) {
int a, b;
scanf("%d %d", &a, &b);
ma[a * MAXN + b]++; //处理重边
ma[b * MAXN + a]++;
addedge(a, b);
addedge(b, a);
}
solve(n);
}
return 0;
}
双联通缩点+染色+建新图+结构体排序去重边:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 200000 + 5;
int low[MAXN], dfn[MAXN], Head[MAXN];
int vis[MAXN], dist[MAXN], stack[MAXN], col[MAXN];
int index_, p, cnt, top, scc;
vector<int> G[MAXN];
struct node_ {
int to;
int next;
bool flag;
bool cut;
}Edge[MAXN * 10];
struct Node {
int a;
int b;
}s[MAXN * 10];
void addEdge(int u, int v, bool Flag) {
Edge[cnt].to = v;
Edge[cnt].next = Head[u];
Edge[cnt].flag = Flag;
Edge[cnt].cut = false;
Head[u] = cnt++;
}
//Tarjan缩点+染色(去重边)
inline void tarjan(int u, int fa, bool tt) {
int v;
low[u] = dfn[u] = ++index_;
stack[top++] = u;
vis[u] = 1;
for(int i = Head[u]; ~i; i = Edge[i].next) {
v = Edge[i].to;
if(v == fa && tt) continue;
if(!dfn[v]) {
tarjan(v, u, Edge[i].flag);
low[u] = min(low[v], low[u]);
if(low[v] > dfn[u]) {
p++;
Edge[i].cut = true;
Edge[i ^ 1].cut = true;
}
}
else if(vis[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) {
scc++;
do {
v = stack[--top];
vis[v] = 0;
col[v] = scc;
} while(v != u);
}
}
bool cmp(Node x, Node y) { //结构体排序去重
if(x.a != y.a) return x.a < y.a;
return x.b < y.b;
}
void init() {
memset(dfn, 0, sizeof(dfn));
memset(Head, -1, sizeof(Head));
memset(s, 0, sizeof(s));
memset(vis, 0, sizeof(vis));
memset(col, 0, sizeof(col));
scc = top = p = index_ = cnt = 0;
for(int i = 0; i < MAXN; ++i) {
G[i].clear();
}
}
void solve(int n) {
for(int i = 1; i <= n; ++i) {
if(!dfn[i]) {
tarjan(i, -1, true);
}
}
for(int i = 1; i <= n; ++i) { //建新图
for(int j = Head[i]; ~j; j = Edge[j].next) {
if(Edge[j].cut) {
G[col[Edge[j].to]].push_back(col[i]);
}
}
}
}
int main() {
int n, m, T;
while(scanf("%d %d", &n, &m) && (n + m)) {
init();
int A, B;
for(int i = 0; i < m; ++i) {
scanf("%d %d", &A, &B);
if(A == B) continue;
s[i].a = min(A, B);
s[i].b = max(A, B);
}
sort(s, s + m, cmp); //去重边
for(int i = 0; i < m; ++i) {
if(!i || (s[i].a != s[i - 1].a || s[i].b != s[i - 1].b)) {
if(s[i].a == s[i + 1].a && s[i].b == s[i + 1].b) {
addEdge(s[i].a, s[i].b, false);
addEdge(s[i].b, s[i].a, false);
}
else {
addEdge(s[i].a, s[i].b, true);
addEdge(s[i].b, s[i].a, true);
}
}
}
solve(n);
}
return 0;
}
缩点+染色+保留点集+建缩点图:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 50010;
int stack[MAXN], col[MAXN], vis[MAXN];
int dfn[MAXN], low[MAXN], in[MAXN], out[MAXN];
int index, top, scc;
vector<int> V[MAXN], G[MAXN];
void init() {
memset(dfn, 0, sizeof(dfn));
memset(vis, 0, sizeof(vis));
memset(out, 0, sizeof(out));
memset(in, 0, sizeof(in));
index = scc = top = 0;
for(int i = 0; i < MAXN; i++) {
V[i].clear();
G[i].clear();
}
}
inline void tarjan(int u) {
int v;
low[u] = dfn[u] = ++index;
stack[top++] = u;
vis[u] = 1;
for(int i = 0; i < V[u].size(); ++i) {
v = V[u][i];
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[v], low[u]);
}
else if(vis[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) {
scc++;
do {
v = stack[--top];
vis[v] = 0;
col[v] = scc; //染色,有利于后续建图
G[scc].push_back(v); //保留每个scc的点集
} while(v != u);
}
}
void solve(int n) {
for(int i = 1; i <= n; ++i) {
if(!dfn[i]) {
tarjan(i);
}
}
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < V[i].size(); ++j) {
int v = V[i][j];
if(col[v] == col[i]) continue;
out[col[i]]++;
}
}
int ans = 0, flag = 0;
for(int i = 1; i <= scc; ++i) {
if(!out[i]) {
ans += G[i].size();
flag++;
}
}
if(flag > 1) printf("0\n"); //不受所有牛欢迎
else printf("%d\n", ans);
}
int main() {
int n, m, A, B;
while(scanf("%d %d", &n, &m) != EOF) {
init();
while(m--) {
scanf("%d %d", &A, &B);
V[A].push_back(B);
}
solve(n);
}
return 0;
}
搭桥模板:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 50010;
int stack[MAXN], col[MAXN], vis[MAXN];
int dfn[MAXN], low[MAXN], in[MAXN], out[MAXN];
int index, top, scc;
vector<int> V[MAXN];
void init() {
memset(dfn, 0, sizeof(dfn));
memset(vis, 0, sizeof(vis));
memset(out, 0, sizeof(out));
memset(in, 0, sizeof(in));
index = scc = top = 0;
for(int i = 0; i < MAXN; i++) {
V[i].clear();
}
}
inline void tarjan(int u) {
int v;
low[u] = dfn[u] = ++index;
stack[top++] = u;
vis[u] = 1;
for(int i = 0; i < V[u].size(); ++i) {
v = V[u][i];
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[v], low[u]);
}
else if(vis[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) {
scc++;
do {
v = stack[--top];
vis[v] = 0;
col[v] = scc;
} while(v != u);
}
}
void solve(int n) {
for(int i = 1; i <= n; ++i) {
if(!dfn[i]) {
tarjan(i);
}
}
//搭桥
if(scc == 1) {
printf("0\n");
return ;
}
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < V[i].size(); ++j) {
int v = V[i][j];
if(col[v] == col[i]) continue;
in[col[v]]++;
out[col[i]]++;
}
}
int ans1 = 0, ans2 = 0;
for(int i = 1; i <= scc; ++i) {
if(!out[i]) ans1++;
if(!in[i]) ans2++;
}
printf("%d\n", max(ans1, ans2));
}
int main() {
int n, m, A, B;
while(scanf("%d %d", &n, &m) != EOF) {
init();
while(m--) {
scanf("%d %d", &A, &B);
V[A].push_back(B);
}
solve(n);
}
return 0;
}