有向图tarjan 求桥 + 求SCC以及里面的点和它的入度 +缩点 模板 【总结】

来源:互联网 发布:上古卷轴5 初始python 编辑:程序博客网 时间:2024/06/03 12:10

引子;给出n个点以及m条单向边

求桥 + 求SCC以及里面的点和它的入度 + 缩点模板

桥 就是 在缩点后 有的两个新点之间会有边—这个边就可以称之为桥
(无向图中也是有桥的,其定义就是如果 把无向图中的桥删除掉,则这个无向图就会被分成两个无向图 )
代码

#include <cstdio>#include <cstring>#include <queue>#include <stack>#include <vector>#include <algorithm>#define MAXN //点数 #define MAXM //边数 #define INF //无穷大 using namespace std;struct Edge{    int from, to, next;    bool cut;//是否为桥 }edge[MAXM];int head[MAXN], edgenum;int low[MAXN], dfn[MAXN];int dfs_clock;int sccno[MAXN], scc_cnt;//记录某个点属于哪个SCC  scc_cnt是SCC计数器 vector<int> scc[MAXN];//存储SCC里面所有点 stack<int> S;//存储点 bool Instack[MAXN];//标记是否在栈里面 vector<int> G[MAXN];//存储缩点后新图int n, m;//n个点 m条单向边 void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v){    Edge E = {u, v, head[u], 0};    edge[edgenum] = E;    head[u] = edgenum++;}void getMap(){    int s, t;    while(m--)    {        scanf("%d%d", &s, &t);        addEdge(s, t);    }}void tarjan(int u, int fa){    int v;    low[u] = dfn[u] = ++dfs_clock;    S.push(u);    Instack[u] = true;    for(int i = head[u]; i != -1; i = edge[i].next)    {        v = edge[i].to;        if(!dfn[v])        {            tarjan(v, u);            low[u] = min(low[u], low[v]);            if(low[v] > dfn[u])//桥             edge[i].cut = true;        }        else if(Instack[v])        low[u] = min(low[u], dfn[v]);    }    if(low[u] == dfn[u])    {        scc_cnt++;//SCC数目加一         scc[scc_cnt].clear();        for(;;)        {            v = S.top(); S.pop();            Instack[v] = false;//出栈             sccno[v] = scc_cnt;//v属于第scc_cnt个SCC             scc[scc_cnt].push_back(v);//存储属于它的所有点             if(v == u) break;        }    }}void find_cut(int l, int r){    memset(low, 0, sizeof(low));    memset(dfn, 0, sizeof(dfn));    memset(sccno, 0, sizeof(sccno));    memset(Instack, false, sizeof(Instack));    dfs_clock = scc_cnt = 0;    for(int i = l; i <= r; i++)    if(!dfn[i]) tarjan(i, -1); }int in[MAXN], out[MAXN];//记录SCC的入度与出度 void suodian()//缩点{    for(int i = 1; i <= scc_cnt; i++) G[i].clear(), in[i] = out[i] = 0;    for(int i = 0; i < edgenum; i++)    {        int u = sccno[edge[i].from];        int v = sccno[edge[i].to];        if(u != v)        G[u].push_back(v), out[u]++, in[v]++;//构建新图 统计入度 出度    } }int main(){    while(scanf("%d%d", &n, &m), n||m)    {        init();        getMap();        find_cut(1, n);//找桥        suodian();        /*到此已找出所有桥和SCC以及SCC里面的点和入度*/    }    return 0;} 
阅读全文
0 0
原创粉丝点击