zoukankan      html  css  js  c++  java
  • tarjan求双联通分量--POJ 1523 +P2860 [USACO06JAN]Redundant Paths G

    概念:

    1. 点双联通: 对于一个连通图,如果任意两点至少存在两条点不重复路径,则称这个图为点双连通的(简称双连通)

    2. 边双联通: 如果任意两点至少存在两条边不重复路径,则称该图为边双连通的

    3. 点双联通分量: 点双连通的极大子图称为点双连通分量(简称双连通分量)

    4. 边双联通分量: 边双连通的极大子图称为边双连通分量

    性质:

    1. 每一个点双连通图中,内部无割点,每一个边双连通图中,内部无桥。

    2. 点双连通图的定义等价于任意两条边都同在一个简单环中,边双连通图的定义等价于任意一条边至少在一个简单环中

    3. 点双连通分量之间以割点连接,且两个点双连通分量之间有且只有一个割点。

    4. 每一个割点可任意属于多个点双连通分量,其余点和每条边只属于且属于一个点双连通分量

    5. 桥不属于任何一个边双连通分量,其余的边和每个顶点都属于且只属于一个边双连通分量

    思考: 一个有桥的连通图,如何把它通过加边变成边双连通图? 结论是:叶子数=1 答案为 0 否则为(叶子数+1)/2

    例题:

    因为只有割点会包含在多个点双联通分量里,所以我们记录每个点包含在多少个点双联通分量里,其中数量>1的就是割点,且等于删掉后形成的联通块个数

    注意: 弹栈的时候不能把割点弹掉,因为我其他点双联通分量里也许会也会有这个割点

    code:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 2e3+10;
    int n,m;
    struct node{
    	int to,next;
    }ed[maxn*2];
    int head[maxn*2],tot;
    void add(int u,int to){
    	ed[++tot].to = to;
    	ed[tot].next = head[u];
    	head[u] = tot;
    }
    int dfn[maxn],low[maxn],cnt,flag;
    int top,st[maxn],bcc,vis[maxn];
    void tarjan(int x,int fa){
        low[x] = dfn[x] = ++cnt;
        st[++top] = x;
        if (x == fa&&head[x] == 0){vis[x]++;return;}
        for(int i = head[x];i;i = ed[i].next){
            int to = ed[i].to;
            if(!dfn[to]){
                tarjan(to,fa);
                low[x] = min(low[x],low[to]);
                if(low[to] >= dfn[x]){
                	bcc++;top++;
                    int y;
                    while (y = st[--top]){
                    	vis[y]++;
                    	if (x == y) break;
                    }
                }
            }
            else low[x] = min(low[x],dfn[to]);
        }
    }
    void init(){
    	memset(head,0,sizeof(head));
    	memset(ed,0,sizeof(ed));
    	memset(vis,0,sizeof(vis));
    	memset(low,0,sizeof(low));
    	memset(dfn,0,sizeof(dfn));
    	top = 0,cnt = 0,tot = 0,bcc = 0,flag = 0;
    }
    int num;
    int main(){
    	int x,y;
    	while (~scanf ("%d",&x)&&x != 0){
    		num++;
    		printf("Network #%d
    ",num);
    		init();
    		int maxx = 0;
    		y = read();
    		if (x != y) add(x,y),add(y,x);
    		maxx = max(maxx,max(x,y));
    		while (~scanf ("%d",&x)&&x != 0){
    			y = read();
    			if (x == y) continue;
    			add(x,y),add(y,x);
    			maxx = max(maxx,max(x,y));
    		}
    		for (int i = 1;i <= maxx;i++){
    			if (!dfn[i]) tarjan(i,i);
    		}
    		for (int i = 1;i <= maxx;i++){
    			if (vis[i] > 1){printf("  SPF node %d leaves %d subnets
    ",i,vis[i]);flag = 1;}
    		}
    		if (!flag) printf("  No SPF nodes
    ");
    		puts("");
    	}
    	return 0;
    }
    

    第二题就可以直接用我们上面思考的结论

    code:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 3e6+10;
    int n,m;
    struct node{
    	int to,next;
    }ed[maxn*2];
    int head[maxn*2],tot = 1;
    void add(int u,int to){
    	ed[++tot].to = to;
    	ed[tot].next = head[u];
    	head[u] = tot;
    }
    int dfn[maxn],low[maxn],cnt,res;
    int bridge[maxn];
    void tarjan(int x, int fa) {
        dfn[x] = low[x] = ++cnt;
        for (int i = head[x];i;i = ed[i].next) {
            int to = ed[i].to;
            if (!dfn[to]) {
                tarjan(to, i);
                low[x] = min(low[x],low[to]);
                if (low[to] > dfn[x])
                    bridge[i] = bridge[i^1] = true;
            }
            else if (i != (fa^1)) low[x] = min(low[x],dfn[to]);
        }
    }
    int col[maxn],dcc=0;
    void dfs(int x,int color){
        col[x]=color;
        for(int i = head[x];i;i = ed[i].next){
                int to = ed[i].to;
                if(bridge[i])continue;
                if(!col[to]) dfs(to,color);
        }
    }
    int du[maxn];
    int main(){
    	n = read(),m = read();
    	for (int i = 1;i <= m;i++){
    		int u = read(),v = read();
    		add(u,v),add(v,u);
    	}
    	for (int i = 1;i <= n;i++){
    		if (!dfn[i]) tarjan(i,0);
    	}
    	int res = 0;
        for(int i = 1;i <= n;i++)
            if(!col[i]) dfs(i,++dcc);
        for (int i = 1;i <= n;i++){
    		for (int j = head[i];j;j = ed[j].next){
    			int to = ed[j].to;
    		//	printf("col[%d] = %d col[%d] = %d
    ",i,col[i],to,col[to]);
    			if (col[to] != col[i]) du[col[to]]++,du[col[i]]++;
    			//printf("du[%d] = %d du[%d] = %d
    ",col[i],du[col[i]],col[to],du[col[to]]);
    		}
    	}
    	int num = 0;
    	for (int i = 1;i <= dcc;i++)
    		if (du[i] == 2) num++;
    	printf("%d
    ",(num+1)/2);
    	return 0;
    }
    
  • 相关阅读:
    CentOS下MySQL忘记root密码解决方法【转载】
    Linux给用户添加sudo权限
    C++11 std::chrono库详解
    npm install Error:EPROTO: protocol error, symlink '../mime/cli.js' -> '/vagrant/src/nodejs/node_modules/express/node_modules/send/node_modules/.bin/mime'
    DOT + graphviz 轻松画图
    关于阿里云ESC上go语言项目编译6l: running gcc failed: Cannot allocate memory
    Ubunu下安装Docker
    Ubunu下安装mongoDB
    Docker私有仓库Registry的搭建验证
    Linux的SOCKET编程详解
  • 原文地址:https://www.cnblogs.com/little-uu/p/13954859.html
Copyright © 2011-2022 走看看