图论常用模板

该模板基于刘汝佳算法竞赛入门经典--训练指南

该模板部分参考自《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) {
          
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值