zoukankan      html  css  js  c++  java
  • POJ 3177 Redundant Paths (tarjan边双连通分量)

    题目连接:http://poj.org/problem?id=3177

    题目大意是给定一些牧场,牧场和牧场之间可能存在道路相连,要求从一个牧场到另一个牧场要有至少两条以上不同的路径,且路径的每条path是分立的独立的,意为不能有公共道路,问最少添加多少条道路达成题目的要求。

    图论问题,因为题目要求不能有公共道路,就是路径不能有公共边。题目转化为求图的边双连通分量,每个边双连通分量内各个牧场肯定存在不同路径可以相互到达,所以要求出图内有多少个边双连通分量,缩点后添边去满足题意。最终缩点后的图为树,所以最简单的办法就是连接树的叶子节点,答案即为树的(叶子节点个数+1)/2。因为是无向图,所以缩点后找到度为1的节点即为叶子节点。

    建双向图,直接跑tarjan求BCC,在求BCC的时候注意是遍历边,而非节点。

    #include<iostream>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    struct node{
    	vector<int> vex;
    	vector<int> num;
    };
    
    struct edge{
    	int a,b,id,cut;
    }E[5005*2];//a为边的起点,b为边的终点,id为边的输入目录 
    
    node g[5005];
    int newnode[5005];
    int bccnum = 0;
    int tot;
    int visit[5005],dfn[5005],low[5005];
    stack<int> stk;
    
    void tarjan(int x,int fa){
    	dfn[x] = low[x] = ++tot;
    	stk.push(x);//节点入栈 
    	for(int i = 0;i<g[x].vex.size() ;i++){
    		int tedge = g[x].num[i]; //边序号,后续可以由边序号作为索引找到该边的id(目录) 
    		
    		if(visit[tedge]){
    			continue;
    		}
    		
    		visit[tedge] = visit[tedge^1] = 1;//标记双向边已经访问过 
    		if(!dfn[g[x].vex[i]]){
    			
    			tarjan(g[x].vex[i],x);
    			low[x] = min(low[x],low[g[x].vex[i]]);
    			
    			if(low[g[x].vex[i]] > dfn[x] ){
    				E[tedge].cut = E[tedge^1].cut = 1;//该tedge边为割边,做标记 
    			}
    		}
    		else
    			low[x] = min(low[x],dfn[g[x].vex[i]]);
    	}
    	
    	if(dfn[x] == low[x]){
    		bccnum++;
    		//找到一个BCC,依次把这个BCC的节点出栈,并做缩点操作 
    		int v;
            do
            {
                v = stk.top() ;
                //visit[v] = 0;
                stk.pop();
                newnode[v] = bccnum;// v节点所属‘bccnum’的边双连通分量 
            }while(v != x);
    	} 
    }
    
    int edgenum = 0;//边的序号从0开始,因为是建立双向边所以两条边标记的序号是异或关系,由边序号可以找到该边的id 
    void addedge(int u,int v,int id){
    	
    	E[edgenum].a = u;
    	E[edgenum].b = v;
    	g[u].num.push_back(edgenum); 
    	E[edgenum++].id = id;
    }
    
    int main(){
    	int F,R;
    	cin>>F>>R;
    	for(int i = 1;i<=R;i++){
    		int u,v;
    		cin>>u>>v;
    		addedge(u,v,i);
    		addedge(v,u,i);
    		g[u].vex.push_back(v);
    		g[v].vex.push_back(u);
    	}
    	
    	for(int i = 1;i<=F;i++){
    		if(!dfn[i]){
    			tarjan(i,0);
    		}
    	}
    	node newG[bccnum+1]; 
    	//cout<<bccnum<<endl;
    	int mark[bccnum+1];
    	memset(mark,0,sizeof(mark));
    	for(int i = 1;i<=F;i++){
    		for(int j = 0;j<g[i].vex.size() ;j++ ){
    			if(E[g[i].num[j]].cut ){ //找到了一个割边 
    				mark[newnode[g[i].vex[j]]] ++;//缩点后该BCC的度++ 
    			}
    		}
    	}
    	int ans = 0;
    	for(int i = 1;i<=bccnum;i++){
    		if(mark[i] == 1){//缩点后度为1的BCC进行统计 
    			//cout<<"x";
    			ans++;
    		}
    	}
    	cout<<(ans+1)/2;
    	return 0;
    }
  • 相关阅读:
    NGINX配置UPSTREAM实现负载均衡
    PHPSTOM 实用LARAVEL 需要附加的 命令
    LINUX 下安装RSYNC
    PHP FLUSH SLEEP 输出缓存控制详解
    YII2-搜索带分页,分页的两种方式
    [weird problem] the xm file transfered by wcf,some sections in it were always repeated
    【原创】解决jquery在ie中不能解析字符串类型xml结构的xml字符串的问题
    jqMobile中pageinit,pagecreate,pageshow等函数的执行顺序
    Jquery Mobile中pageinit等函数执行两次的问题【终极解决】
    jqMobile中的dialog和popup的区别
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12129652.html
Copyright © 2011-2022 走看看