一、dfs框架:

 vector<int>G[maxn];  //存图
int vis[maxn]; //节点访问标记
void dfs(int u)
{
vis[u] = ;
PREVISIT(u); //访问节点u之前的操作
int d = G[u].size();
for(int i = ; i < d; i++)//枚举每条边
{
int v = G[u][i];
if(!vis[v])dfs(v);
}
POSTVISIT(u); //访问节点u之后的操作
}

二、无向图连通分量

 void find_cc()
{
current_cc = ;//全局变量 连通块编号
memset(vis, , sizeof(vis));
for(int u = ; u < n; u++)if(!vis[u])//依次检查每个节点,如果未访问过,说明它属于一个新的连通分量,从该点dfs访问整个连通分量
{
current_cc++;
dfs(u);
}
}

三、二分图判定

调用之前,清空color数组,调用之前,先给color[u]赋值1

 int color[maxn];//0表示未染色 1表示白色 2表示黑色
bool bipartite(int u)
{
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
if(color[u] == color[v])return false;//u v颜色一样
if(!color[v])
{
color[v] = - color[u];//节点u与v染不同的颜色
if(!bipartite(v))return false;
}
}
return true;
}

四、无向图的割点和桥

加入时间戳

int dfs_clock;
void PREVISIT(int u){pre[u] = ++dfs_clock;}
void POSTVISIT(int u){post[u] = ++dfs_clock;}

注意:求桥的时候注意重边

求割点和桥可以用下面求双连通分量的代码

五、无向图的双连通分量

点-双连通分量

 struct Edge
{
int u, v;
Edge(){}
Edge(int u, int v):u(u), v(v){}
};
int pre[maxn];//时间戳数组
int iscut[maxn];//割点
int bccno[maxn];//点-双连通分量编号 (割点的编号没有意义)
int dfs_clock, bcc_cnt;//时间戳 双连通分量编号
vector<int>G[maxn], bcc[maxn];//G存储图 bcc存储每个双连通分量的点
stack<Edge>S; int dfs(int u, int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = ;
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
Edge e(u, v);
if(!pre[v])
{
S.push(e);
child++;
int lowv = dfs(v, u);
lowu = Min(lowu, lowv);
if(lowv >= pre[u])
{
iscut[u] = ;
bcc_cnt++;
bcc[bcc_cnt].clear();
for(;;)
{
Edge x = S.top();
S.pop();
if(bccno[x.u] != bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u] = bcc_cnt;}
if(bccno[x.v] != bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v] = bcc_cnt;}
if(x.u == u && x.v == v)break;
}
}
}
else if(pre[v] < pre[u] && v != fa)
{
S.push(e);
lowu = Min(lowu, pre[v]);
}
}
if(fa < && child == )iscut[u] = ;
return lowu;
}
void find_bcc(int n)//求解点-双连通分量
{
Mem(pre);
Mem(iscut);
Mem(bccno);
dfs_clock = bcc_cnt = ;
for(int i = ; i < n; i++)if(!pre[i])dfs(i, -);
}

边-双连通分量

 struct Edge
{
int u, v;
Edge(){}
Edge(int u, int v):u(u), v(v){}
};
int pre[maxn];//时间戳数组
int isbridge[maxm];//桥
int bccno[maxn];//边-双连通分量编号 (任意两个无交集)
int low[maxn];//low[u]为u后代可以返回的最早祖先值
int dfs_clock, bcc_cnt;//时间戳 双连通分量编号
vector<Edge>e;//存边
vector<int>G[maxn], bcc[maxn];//G存储图 bcc存储每个双连通分量的点
//G存边在e中的下标
void init(int n)
{
for(int i = ; i < n; i++)G[i].clear();
e.clear();
}
void addedge(int u, int v)//双向边
{
e.push_back(Edge(u, v));
G[u].push_back(e.size() - );
e.push_back(Edge(v, u));
G[v].push_back(e.size() - );//正好满足双向边^操作
}
void dfs1(int u, int fa)//找出所有的桥
{
low[u] = pre[u] = ++dfs_clock;
for(int i = ; i < G[u].size(); i++)
{
int v = e[G[u][i]].v;
if(!pre[v])
{
dfs1(v, u);
low[u] = Min(low[u], low[v]);
if(low[v] > pre[u])//是桥,双向边均标记一下
{
isbridge[G[u][i]] = isbridge[G[u][i]^] = ;
}
}
else if(pre[v] < pre[u] && v != fa)
{
low[u] = Min(low[u], pre[v]);
}
}
}
void dfs2(int u)//dfs染色找边-双连通分量即可
{
pre[u] = ;//vis数组标记
bccno[u] = bcc_cnt;
bcc[bcc_cnt].push_back(u);
for(int i = ; i < G[u].size(); i++)
{
int v = e[G[u][i]].v;
if(isbridge[G[u][i]])continue;//不走桥
if(!pre[v])dfs2(v);
}
}
void find_bcc(int n)//求解边-双连通分量
{
Mem(pre);Mem(isbridge);Mem(bccno);Mem(low);
dfs_clock = bcc_cnt = ;
for(int i = ; i < n; i++)if(!pre[i])dfs1(i, -);
Mem(pre);
for(int i = ; i < n; i++)if(!pre[i]){bcc_cnt++; bcc[bcc_cnt].clear(); dfs2(i);}
}

六、有向图的强连通分量

 vector<int>G[maxn];
int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
stack<int>S;
void dfs(int u)
{
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u);
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
if(!pre[v])
{
dfs(v);
lowlink[u] = Min(lowlink[u], lowlink[v]);
}
else if(!sccno[v])
{
lowlink[u] = Min(lowlink[u], pre[v]);
}
}
if(lowlink[u] == pre[u])
{
scc_cnt++;
for(;;)
{
int x = S.top();
S.pop();
sccno[x] = scc_cnt;
if(x == u)break;
}
}
}
void find_scc(int n)
{
dfs_clock = scc_cnt = ;
Mem(sccno);
Mem(pre);
for(int i = ; i < n; i++)if(!pre[i])dfs(i);
}

七、2-SAT问题

 struct TwoSAT
{
int n;
vector<int>G[maxn * ];
bool mark[maxn * ];
int S[maxn * ], c;
bool dfs(int x)
{
if(mark[x^])return false;
if(mark[x])return true;
mark[x] = true;
S[c++] = x;
for(int i = ; i < G[x].size(); i++)
if(!dfs(G[x][i]))return false;
return true;
}
void init(int n)
{
this->n = n;
for(int i = ; i < n * ; i++)G[i].clear();
Mem(mark);
}
//x = xval or y = yval
void add_clause(int x, int xval, int y, int yval)
{
x = x * + xval;
y = y * + yval;
G[x ^ ].push_back(y);
G[y ^ ].push_back(x);
}
bool solve()
{
for(int i = ; i < n * ; i += )
{
if(!mark[i] && !mark[i + ])
{
c = ;
if(!dfs(i))
{
while(c > )mark[S[--c]] = false;
if(!dfs(i + ))return false;
}
}
}
return true;
}
};

DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)的更多相关文章

  1. POJ 1144 Network(无向图的割顶和桥模板题)

    http://poj.org/problem?id=1144 题意: 给出图,求割点数. 思路: 关于无向图的割顶和桥,这篇博客写的挺不错,有不懂的可以去看一下http://blog.csdn.net ...

  2. 图论(无向图的割顶):POJ 1144 Network

    Network   Description A Telephone Line Company (TLC) is establishing a new telephone cable network. ...

  3. Tarjan求割点(割顶) 割边(桥)

    割点的定义: 感性理解,所谓割点就是在无向连通图中去掉这个点和所有和这个点有关的边之后,原先连通的块就会相互分离变成至少两个分离的连通块的点. 举个例子: 图中的4号点就是割点,因为去掉4号点和有关边 ...

  4. UVA 315 :Network (无向图求割顶)

    题目链接 题意:求所给无向图中一共有多少个割顶 用的lrj训练指南P314的模板 #include<bits/stdc++.h> using namespace std; typedef ...

  5. POJ1144 Network 无向图的割顶

    现在打算重新学习图论的一些基础算法,包括像桥,割顶,双连通分量,强连通分量这些基础算法我都打算重敲一次,因为这些量都是可以用tarjan的算法求得的,这次的割顶算是对tarjan的那一类算法的理解的再 ...

  6. 【数据结构】DFS求有向图的强连通分量

    用十字链表结构写的,根据数据结构书上的描述和自己的理解实现.但理解的不透彻,所以不知道有没有错误.但实验了几个都ok. #include <iostream> #include <v ...

  7. 无向图求割(找桥)tarjan

    本博客参考了李煜东的<算法竞赛进阶指南>,大家要是觉得这篇文章写的不错请大家支持正版.豆瓣图书 我在之前的博客中讲解了搜索序时间戳,这次我们讲讲追溯值的概念. 追溯值: 设subtree( ...

  8. P3388 【模板】割点(割顶)&& 桥

    题目背景 割点 题目描述 给出一个n个点,m条边的无向图,求图的割点. 输入输出格式 输入格式: 第一行输入n,m 下面m行每行输入x,y表示x到y有一条边 输出格式: 第一行输出割点个数 第二行按照 ...

  9. Spoj 2878 KNIGHTS - Knights of the Round Table | 双联通分量 二分图判定

    题目链接 考虑建立原图的补图,即如果两个骑士不互相憎恨,就在他们之间连一条无向边. 显而易见的是,如果若干个骑士在同一个点数为奇数的环上时,他们就可以在一起开会.换句话说,如果一个骑士被一个奇环包含, ...

随机推荐

  1. 这些天C#面试有感

    为何面试 为何面试! 还用问?肯定是因为要离职啊 - -!离职原因就不说了,说来说去就是那么几个原因:这里主要讲我这些天面试遇到的问题,以及对面试的一些感受吧[断续更新

  2. [日常] Go语言圣经-竞争条件习题

    package main import( "fmt" "sync" ) var balance int func Deposit(amount int) { b ...

  3. 从实例角度分析java的public、protected、private和default访问权限

    一.public 同一个package 1.本类内部 public class A { public int f=1; public void m1() {} public void m2() { f ...

  4. Android - 富文本编辑器

    Android富文本编辑器(一):基础知识 目前主流的基于Android富文本开发方式思路如下: 基于TextView图文混排 使用方式: TextView textView = new TextVi ...

  5. spring-bean实例化三种方式

    在spring中,bean的示例化有三种方式. 1.使用类的无参构造函数创建 2.使用静态工厂方式创建 3.使用实例化工厂方式创建. 具体代码如下 静态工厂方式: Bean2.java package ...

  6. Flask 中路由系统

    1. @app.route() 装饰器中的参数 methods : 当前 url 地址,允许访问的请求方式 @app.route("/info", methods=["G ...

  7. js-ES6学习笔记-变量的解构赋值

    1.ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 2.ES6允许写成:let [a,b,c] = [1,2,3];上面代码表示,可以从数 ...

  8. Dynamics 365Online 使用adal.js注册和配置SimpleSPA应用程序

    本篇是基于dynamics 365online撰写,本文中使用的365online及azure均为试用版,因为online在国内还没落地,所以我申请的是新加坡版,online的申请方式可见我之前的博文 ...

  9. Ubuntu16.10上安装NodeJS6.9.2

    1.下载 https://nodejs.org/en/download/ 2.解压 tar -xJf node-v6.9.2-linux-x64.tar.xz 3. 移到通用的软件安装目录 /opt/ ...

  10. mui中图片手势缩放功能的实现

    MUI框架,要实现手势缩放图片,可以使用imageviewer组件来实现.代码很简单: 引入css: <link href="assets/css/mui.imageviewer.cs ...