zoukankan      html  css  js  c++  java
  • UVA796 Critical Links(求桥) 题解

    题意:求桥

    思路:求桥的条件是:(u,v)是父子边时 low[v]>dfn[u] 

    所以我们要解决的问题是怎么判断u,v是父子边(也叫树枝边)。我们在进行dfs的时候,要加入一个fa表示当前进行搜索的点的父节点。v=edge[v].v,如果dfn[v]==0即没访问过,那么肯定是父子边;如果v已经被访问过,我们就要做出筛选,只有v!=fa才进行low[u]=min(low[u],dfn[v]),因为v==fa时,(u,v)变成了返祖边,这时候low[u]被刷新成为fa的dfn,但是low是通过父子边所能找到的最早节点,固要舍去这种情况。

    无向连通图的割点、桥

    code:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<string>
    #include<map>
    #include<stack> 
    #include<set>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    #include<sstream>
    #define ll long long 
    const int N=1e5+5;
    const ll INF=1e5+5;
    using namespace std;
    int n,m,cnt,ecnt,num;
    int dfn[N],low[N],head[N];
    vector<int> g[N];
    struct Edge{
    	int u,v,next;
    }edge[N*10];
    struct Ans{
    	int u,v;
    }ans[N*10];
    int cmp(Ans a,Ans b){
    	if(a.u<b.u) return 1;
    	else if(a.u==b.u && a.v<b.v) return 1;
    	return 0;
    }
    void add(int u,int v){
    	edge[num].u=u;
    	edge[num].v=v;
    	edge[num].next=head[u];	//表头 
    	head[u]=num++;
    } 
    
    void tarjan(int x,int fa){	//fa是x的父节点 
    	dfn[x]=low[x]=++cnt;
    	for(int i=head[x];i!=-1;i=edge[i].next){
    		int v=edge[i].v;
    		if(!dfn[v]){
    			tarjan(v,x);
    			low[x]=min(low[x],low[v]);
    			if(low[v]>dfn[x]){
    				int a,b;
    				a=x,b=v;
    				if(a>b) swap(a,b);
    				ans[ecnt].u=a,ans[ecnt].v=b;
    				ecnt++;		
    			}
    		}
    		else if(v!=fa){
    			low[x]=min(low[x],dfn[v]);
    		}
    		
    	}
    }
    void init(){ 
    	cnt=ecnt=num=0;
    	memset(head,-1,sizeof(head));
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    }
    int main(){
    	int t,T,a,b,n;
    	while(~scanf("%d",&t)){
    		init();
    		T=t;
    		while(T--){
    			scanf("%d (%d)",&a,&n);
    			while(n--){
    				scanf("%d",&b);
    				add(a,b);
    			}
    		}
    		for(int i=0;i<t;i++){
    			if(!dfn[i]) tarjan(i,i);
    		}
    		sort(ans,ans+ecnt,cmp);
    		cout<<ecnt<<" critical links"<<endl;
    		for(int i=0;i<ecnt;i++){
    			printf("%d - %d
    ",ans[i].u,ans[i].v);
    		}
    		cout<<endl;
    	}
        return 0;
    }

    这是在加边的时候判断是否重边

    code2:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<string>
    #include<map>
    #include<stack> 
    #include<set>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    #include<sstream>
    #define ll long long 
    const int N=1e5+5;
    const ll INF=1e5+5;
    using namespace std;
    int n,m,cnt,ecnt,num;
    int dfn[N],low[N],head[N];
    vector<int> g[N];
    struct Edge{
    	int u,v,next;
    	int flag;
    }edge[N*10];
    struct Ans{
    	int u,v;
    }ans[N*10];
    int cmp(Ans a,Ans b){
    	if(a.u<b.u) return 1;
    	else if(a.u==b.u && a.v<b.v) return 1;
    	return 0;
    }
    void add(int u,int v){
    	for(int i=head[u];i!=-1;i=edge[i].next){
    		if(edge[i].v==v){	//说明不是桥 
    			edge[i].flag++;
    			edge[num].u=u;
    			edge[num].v=v;
    			edge[num].flag=1;
    			edge[num].next=head[u];	//表头 
    			head[u]=num++;
    			return;
    		}
    	}
    	edge[num].u=u;
    	edge[num].v=v;
    	edge[num].flag=0;
    	edge[num].next=head[u];	//表头 
    	head[u]=num++;
    } 
    
    void tarjan(int x,int fa){	//fa是x的父节点 
    	dfn[x]=low[x]=++cnt;
    	for(int i=head[x];i!=-1;i=edge[i].next){
    		int v=edge[i].v;
    		if(v==fa) continue;
    		if(!dfn[v]){
    			tarjan(v,x);
    			low[x]=min(low[x],low[v]);
    			if(low[v]>dfn[x] && edge[i].flag==0){
    				int a,b;
    				a=x,b=v;
    				if(a>b) swap(a,b);
    				ans[ecnt].u=a,ans[ecnt].v=b;
    				ecnt++;		
    			}
    		}
    		else{
    			low[x]=min(low[x],dfn[v]);
    		}
    		
    	}
    }
    void init(){ 
    	cnt=ecnt=num=0;
    	memset(head,-1,sizeof(head));
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    }
    int main(){
    	int t,T,a,b,n;
    	while(~scanf("%d",&t)){
    		init();
    		T=t;
    		while(T--){
    			scanf("%d (%d)",&a,&n);
    			while(n--){
    				scanf("%d",&b);
    				add(a,b);    //这里不能加add(b,a),在读到b时会加这条边,否则在下一次add(b,a)会判重边
    			}
    		}
    		for(int i=0;i<t;i++){
    			if(!dfn[i]) tarjan(i,i);
    		}
    		sort(ans,ans+ecnt,cmp);
    		cout<<ecnt<<" critical links"<<endl;
    		for(int i=0;i<ecnt;i++){
    			printf("%d - %d
    ",ans[i].u,ans[i].v);
    		}
    		cout<<endl;
    	}
        return 0;
    }

  • 相关阅读:
    【Mysql 8001错误
    【mysql查询今天、昨天、7天、近30天、本月、上一月 数据】
    bootstrap-table 常用总结-1
    前端下载图片
    swiper 轮播中常用的效果,持续更新
    常用的时间函数整理
    拼接字符转的转义
    Ajax跨域请求,设置content
    JS MD5 返回二进制格式
    jqgrid three 树形结构
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9409104.html
Copyright © 2011-2022 走看看