zoukankan      html  css  js  c++  java
  • tarjan,割边,桥,割点

    这里是tarjan的基础知识,

    求割点和割边


    先来求割边,

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <bits/stdc++.h>
      4 using namespace std;
      5 typedef long long ll;
      6 typedef unsigned long long ull;
      7 
      8 #define ls (t<<1)
      9 #define rs ((t<<1)|1)
     10 #define mid ((l+r)>>1)
     11 
     12 #define mk make_pair
     13 #define pb push_back
     14 #define fi first
     15 #define se second
     16 
     17 #define MAXN 100001
     18 struct edge {
     19     int v,nxt;
     20 } e[MAXN*2];
     21 int head[MAXN];
     22 bool qiao[MAXN*2];
     23 int dfn[MAXN],low[MAXN];
     24 int n,m,cnt,num;
     25 int c[MAXN],dcc;
     26 //c[i]为i节点所在边双联通块编号 
     27 void add(int x,int y) {
     28     e[++cnt].v=y,e[cnt].nxt=head[x],head[x]=cnt;
     29 }
     30 void tarjan(int x,int fa) {
     31     dfn[x]=low[x]=++num;
     32     for (int i=head[x]; i; i=e[i].nxt) {
     33         int y=e[i].v;
     34         if (!dfn[y]) {
     35             tarjan(y,i);
     36             low[x]=min(low[x],low[y]);
     37             if (low[y]>dfn[x]) {
     38                 qiao[i]=qiao[i^1]=1;
     39             }
     40         } else if(i!=(fa^1)) {
     41             low[x]=min(low[x],dfn[y]);
     42         }
     43     }
     44 }
     45 
     46 void dfs(int x) {
     47     c[x]=dcc;
     48     for (int i=head[x];i;i=e[i].nxt) {
     49         int y=e[i].v;
     50         if (c[y]||qiao[i]) continue;
     51         dfs(y);
     52     }
     53 }
     54 
     55 struct newedge{
     56     int v,nxt;
     57 }newe[MAXN*2];
     58 int newhead[MAXN],newcnt;
     59 void newadd(int x,int y) {
     60     newe[++newcnt].v=y;
     61     newe[newcnt].nxt=newhead[x];
     62     newhead[x]=newcnt;
     63 }
     64 
     65 int main() {
     66     cin>>n>>m;
     67     cnt=1;
     68     for (int i=1,x,y; i<=m; i++) {
     69         cin>>x>>y;
     70         add(x,y),add(y,x);
     71     }
     72     for (int i=1; i<=n; i++) {
     73         if (!dfn[i]) {
     74             tarjan(i,0);
     75         }
     76     }
     77     for (int i=1;i<=n;i++) {
     78         if (!c[i]) {
     79             ++dcc;
     80             dfs(i);
     81         }
     82     }
     83     for (int i=2; i<cnt; i+=2) {
     84         if (qiao[i]) {
     85             cout<<e[i^1].v<<" "<<e[i].v<<"是桥"<<endl;
     86         }
     87     }
     88     cout<<endl;
     89     cout<<"边双联通块有"<<dcc<<""<<endl;
     90     for (int i=1;i<=n;i++) {
     91         cout<<i<<" "<<"belongs"<<" "<<c[i]<<endl;
     92     }
     93     newcnt=1;
     94     for (int i=2;i<=cnt;i++) {
     95         int x=e[i^1].v,y=e[i].v;
     96         if (c[x]==c[y]) continue;
     97         newadd(c[x],c[y]);
     98     }
     99     cout<<"缩点后点数"<<dcc<<" 边数"<<newcnt/2<<endl;
    100     for (int i=2;i<newcnt;i++) {
    101         cout<<newe[i^1].v<<" "<<newe[i].v<<"是一条边"<<endl;
    102     }
    103     return 0;
    104 }
    105 
    106 /*
    107 12 15
    108 1 2
    109 1 3
    110 2 3
    111 2 4
    112 3 5
    113 4 5
    114 1 6
    115 6 7
    116 6 8
    117 7 8
    118 7 9
    119 7 10
    120 10 11
    121 10 12
    122 11 12
    123 */


    下面是割点

    #include <cstdio>
    #include <iostream>
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    #define pb push_back
    #define MAXN 100001
    struct edge {
        int v,nxt;
    } e[MAXN*2];
    int head[MAXN];
    bool cut[MAXN];
    int dfn[MAXN],low[MAXN];
    int n,m,cnt,num,root;
    vector <int> dcc[MAXN];
    int ccnt;//用于存dcc数组 
    //dcc[i]保存编号为i的点双联通块内全部节点
    int s[MAXN],top;//
    int c[MAXN];
    //c[i]表示表示i所属v-DCC编号 
    void add(int x,int y) {
        e[++cnt].v=y,e[cnt].nxt=head[x],head[x]=cnt;
    }
    void tarjan(int x) {
        dfn[x]=low[x]=++num;
        s[++top]=x;
        if (x!=root&&head[x]==0) {
            dcc[++ccnt].pb(x);
            return;
        }
        int flag=0;
        for (int i=head[x]; i; i=e[i].nxt) {
            int y=e[i].v;
            if (!dfn[y]) {
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if (low[y]>=dfn[x]) {
                    flag++;
                    if (x!=root||flag>1) {
                        cut[x]=1;
                    }
                    ccnt++;
                    int z;
                    do{
                        z=s[top--];
                        dcc[ccnt].pb(z);
                    }while(z!=y);
                    dcc[ccnt].pb(x);
                }
            } 
            else low[x]=min(low[x],dfn[y]);
        }
    }
    
    struct newedge{
        int v,nxt;
    }newe[MAXN*2];
    int newhead[MAXN],tc;
    int new_id[MAXN];
    void newadd(int x,int y) {
        newe[++tc].v=y;
        newe[tc].nxt=newhead[x];
        newhead[x]=tc;
    }
    
    int main() {
        cin>>n>>m;
        cnt=1;
        for (int i=1,x,y; i<=m; i++) {
            cin>>x>>y;
            if (x==y) continue;
            add(x,y),add(y,x);
        }
        for (int i=1; i<=n; i++) {
            if (!dfn[i]) {
                root=i;
                tarjan(i);
            }
        }
        for (int i=1; i<=n; i++) {
            if (cut[i]) {
                cout<<i<<" ";
            }
        }  
        cout<<"是个割点"<<endl;
        for (int i=1;i<=ccnt;i++) {
            cout<<"v-DCC "<<i<<" : ";
            for (int j=0;j<dcc[i].size();j++) {
                cout<<" "<<dcc[i][j];
            }
            cout<<endl;
        }
        num=ccnt;
        for (int i=1;i<=n;i++) {
            if (cut[i]) new_id[i]=++num;
        }
        tc=1;
        for (int i=1;i<=ccnt;i++) {
            for (int j=0;j<dcc[i].size();j++) {
                int x=dcc[i][j];
                if (cut[x]) {
                    newadd(i,new_id[x]);
                    newadd(new_id[x],i);
                } 
                else c[x]=i;
            }
        }
        cout<<"缩点后森林点数 "<<num<<" 边数 "<<tc/2<<endl;
        printf("编号 1~%d 的为原图v-DCC,编号 >%d 的为原图割点
    ",ccnt,ccnt);
        for (int i=2;i<tc;i+=2) {
            cout<<newe[i^1].v<<" "<<newe[i].v<<endl;
        } 
        
        return 0;
    }
    
    /*
    12 15
    1 2
    1 3
    2 3
    2 4
    3 5
    4 5
    1 6
    6 7
    6 8
    7 8
    7 9
    7 10
    10 11
    10 12
    11 12
    */
    
    /*
    8 11
    1 2
    1 5
    2 5
    2 3
    3 4
    4 5
    1 6
    6 7
    6 8
    6 9
    8 9
    
    */
  • 相关阅读:
    C#开发PACS医学影像处理系统(十九):Dicom影像放大镜
    C#开发PACS医学影像处理系统(十八):Dicom使用LUT色彩增强和反色
    C#开发PACS医学影像处理系统(十七):2D处理之影像旋转和翻转
    C#开发PACS医学影像处理系统(十六):2D处理之影像平移和缩放
    C#开发PACS医学影像处理系统(十五):Dicom影像交叉定位线算法
    C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位
    C#开发PACS医学影像处理系统(十三):绘图处理之病灶测量
    C#开发PACS医学影像处理系统(一):开发背景和功能预览
    C#开发PACS医学影像处理系统(二):界面布局之菜单栏
    C#开发PACS医学影像处理系统(三):界面布局之工具栏
  • 原文地址:https://www.cnblogs.com/codemaker-li/p/9800832.html
Copyright © 2011-2022 走看看