该模板基于刘汝佳算法竞赛入门经典--训练指南
该模板部分参考自《ACM国际大学生程序设计竞赛--算法与实现》
图论常用模板
转载请注明:转自http://blog.youkuaiyun.com/a15129395718
新的独立博客,欢迎访问: http://zihengoi.cn
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1000;
const int INF = 0x3f3f3f3f;
//染色
//判断结点u所在的连通分量是否为二分图
//未染色结点值为0, 已染色结点值为1/2.
int color[MAXN];
bool bipartite(int u) {
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i]; //枚举每条边(u, v)
if(color[v] == color[u]) return false;//结点v已着色,且和结点u的颜色冲突
if(!color[v]) {
color[v] = 3 - color[u]; //给结点v着与结点u相反的颜色
if(!bipartite(v)) return false;
}
}
return true;
}
//无向图求桥求割
struct Edge{
int v, w;
bool cut;
Edge(int v, int w, int cnt = false) : v(v), w(w), cut(cut) {}
};
bool iscut[MAXN];
vector<Edge> G[MAXN];
int dfs_clock, low[MAXN], pre[MAXN];
int dfs(int u, int fa) { //u在DFS树中的父节点是fa
int lowu = pre[u] = ++dfs_clock;
bool flag = false;
int child = 0; //子节点数目
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if(!pre[v]) {
child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv); //用后代的low函数更新u的low函数
if(lowv >= pre[u]) {
if(lowv > pre[u]) G[u][i].cut = true;
iscut[u] = true;
}
} else if(v == fa) {
if(flag) lowu = min(lowu, pre[v]);
flag = true;
} else lowu = min(lowu, pre[v]); //用反向边更新u的low函数
}
if(fa < 0 && child == 1) iscut[u] = 0;
low[u] = lowu;
return lowu;
}
//有向图的强连通分量
vector<int> G[MAXN];
int pre[MAXN], low[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
stack<int> S;
void Tarjan(int u) {
pre[u] = low[u] = ++dfs_clock;
S.push(u);
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!pre[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
} else if(!sccno[v]) low[u] = min(low[u], pre[v]);
}
if(low[u] == pre[u]) {
scc_cnt++;
while(true) {