Tarjan:求解图的割点和割边

#include<iostream>
#include <vector>
#include <string.h>
#include <algorithm>

using namespace std;

const int nMax = 100000+10;
bool cut[nMax];   
int Dfn[nMax], low[nMax], parent[nMax]; 
int vis[nMax];

vector<int> adj[nMax], CutEdge[nMax];

void addEdge(int u, int v) {
    adj[u].push_back(v);
    adj[v].push_back(u);
}

void findcut(int dep, int u) {
	
    Dfn[u] = low[u] = dep;
    
    for (int i=0; i<adj[u].size(); i++) {
        int v = adj[u][i];
     //   cout << v << ":"<<dfn[v]<< endl;
        
        //if (!dfn[v])//用这个条件判断会出现错误...... 
        if(!vis[v]) 
		 {
		 	vis[v] = true;
        	parent[v] = u; 
   //     	cout << v <<"parent" << u << endl; 
            findcut(dep+1, v);
            
			/*if (u == rt)
                rt_num++;*/
        
                low[u] = min(low[u], low[v]);//确保low[u]最小
                
				if (low[v] >= Dfn[u])//1 :: 1 1  3 :: 2 2 
                {
             //   	cout << parent[v] << endl;
					cut[u] = true; //在例子中....1被3拖出来了......明明1是叶子结点...(ps:找出问题啦。。不能以dfn作为判断条件...不过不明白...明明走过了的确就不为0了 
					CutEdge[u].push_back(v);//割边 
/*
7 6
1 3
2 3
3 4
3 5
4 5
5 6
*/ 
			//		cout<< v << ":" << u << CutEdge[u].size() << endl; //如果满足这个条件则u 为割点,//u-v即为割边 
				}
        }
        else if(parent[u] != v && Dfn[v] < low[u])//v的父节点不能用来跟新他的low值 
     {
     	int tmp = low[u];
     
//	 cout << v << "parent" << parent[v] << "u:" << u << endl;   
	 	low[u] = min(low[u],Dfn[v]);//回溯继续
//	 		if(u == 3 && low[3] == 1) cout <<parent[3] << v << endl; 
//	 cout<< u << "修改前后比较:"<< tmp << " :" << low[u] << " :" << v << endl; 
 }
    }

//		cout << "此时的" << ":" << low[u] << "	"  << u << "   u: " << dfn[u] <<endl;
}		


    int main() {

        //初始化
        for(int i=0; i<nMax; i++){ 
			adj[i].clear();
			CutEdge[i].clear();
		} 
       

        int u, v, n, m;
        while (~scanf("%d%d", &n, &m))
        {
        memset(vis, false, sizeof(vis)); 
        memset(cut, false, sizeof(cut));
     //   memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
		memset(parent, 0, sizeof(parent));
		    //e = 0;
          //  memset(head, -1, sizeof(head));
            for(int i=0; i<m; i++){
                cin >> u >> v;
                addEdge(u, v);
                addEdge(v, u); 
            }

            //建好图后调用
           for(int i=1; i<=n; i++)
         	  findcut(1, i); //以i为根节点,可以在下次选另一点为根节点时,判断上次的根结点 是否为割点
			//另一种判断根节点是否为割点,及判断根结点有几颗子树,代码如下:
/*		Dfn[1] = low[1] = 1;
		int childTree = 0;
		for (int i=0; i<adj[1].size(); i++) {
            int w = adj[1][i];
            if(!vis[w]){
                vis[w] = true;
                parent[w] = 0;
                findcut(2, w);
            
			    if(low[w] > Dfn[1]){
                    CutEdge[1].push_back(w);
                }
                childTree++;
            }
        }
        
        if(childTree >= 2){//根顶点是割点的条件
            cut[1] = true;
        } */
            
            
        //输出割点个数    
                int cnt = 0;
                
                for(int i=1; i<=n; i++){
                	if(cut[i] == true){
                		cnt++;
					}
				}
				
				cout<< cnt << endl;
				
				
        for(int i=1; i<=n; i++){
        	for(int j=0; j<CutEdge[i].size(); j++){
        		cout << i << "---" << CutEdge[i][j] <<endl;
			}
			cout <<i << "size" << CutEdge[i].size() << endl;
		}
        
        }
        
        
    

        //则cut 中为 true 的即为割点
        return 0;
   }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值