Network UVA - 315 (tarjan+割点)

16 篇文章 0 订阅
2 篇文章 0 订阅

Network

 UVA - 315 

A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N. No two places have the same number. The lines are bidirectional and always connect together two places and in each place the lines end in a telephone exchange. There is one telephone exchange in each place. From each place it is possible to reach through lines every other place, however it need not be a direct connection, it can go through several exchanges. From time to time the power supply fails at a place and then the exchange does not operate. The officials from TLC realized that in such a case it can happen that besides the fact that the place with the failure is unreachable, this can also cause that some other places cannot connect to each other. In such a case we will say the place (where the failure occured) is critical. Now the officials are trying to write a program for finding the number of all such critical places. Help them. Input The input file consists of several blocks of lines. Each block describes one network. In the first line of each block there is the number of places N < 100. Each of the next at most N lines contains the number of a place followed by the numbers of some places to which there is a direct line from this place. These at most N lines completely describe the network, i.e., each direct connection of two places in the network is contained at least in one row. All numbers in one line are separated by one space. Each block ends with a line containing just ‘0’. The last block has only one line with N = 0. Output The output contains for each block except the last in the input file one line containing the number of critical places.

Sample Input 5 5 1 2 3 4 0 6 2 1 3 5 4 6 2 0 0

Sample Output 1 2

给了一个无向图,求割点,模板裸题。

割点:

分情况:

1,如果u是搜索树的根节点并且u有两个用以上子节点,则u是割点

2.如果u不是根节点,若满足dfn[u]<=low[v](v不能访问到u的祖先(无回祖边)),则u是割点

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 1e3 + 7;
const int M = 1e5 + 7;
int head[N], en;
struct Edge {
	int u, v, to;
} e[M];
void addedge (int u, int v) {
	e[++en].u = u;
	e[en].v = v;
	e[en].to = head[u];
	head[u] = en; 
}
//dfn当前点的时间戳, low当前点能访问到的最小时间戳
//isgd记录是否割点, root根,deep时间戳 
int dfn[N], low[N], isgd[N], root, deep;
void init() { //初始化 
	memset(head, -1, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(isgd, 0, sizeof(isgd));
	en = deep = 0;
}
//求割点 
void tarjan(int u, int father) {
	low[u] = dfn[u] = ++deep;
	int child = 0; //孩子个数  
	for (int i = head[u]; ~i; i = e[i].to) {
		int v = e[i].v;
		if (!dfn[v]) { //如果是第一次访问 
			++child;
			tarjan(v, u);
			low[u] = min(low[u], low[v]); 更新能访问到的最小时间戳,因为u与当前点相连所以更新为u点能访问到的最小时间戳  
			if (u != root && low[v] >= dfn[u]) isgd[u] = 1; //如果不是根节点,且存在一个节点在删除当前点的情况下不能再访问到当前点的祖先 
			if (u == root && child >= 2) isgd[u] = 1; //如果当前点是根节点且有两个以上的子节点 //则当前点是割点
		} else if (v != father) { //如果点曾经被访问过,且不是当前点的父节点,则更新当前点能访问到的最小时间戳
			low[u] = min(low[u], dfn[v]);
		}
	}
 
 }
int main() {
	
	int n;
	while (~scanf ("%d", &n) && n) {
		int u, v;
		init();
		while (~scanf ("%d", &u) && u) {
			while (~scanf ("%d", &v)) {
				addedge (u, v);
				addedge (v, u);
				if (getchar() == '\n') break;
			}
		}
		for (int i = 1; i <= n; ++i) {
			if (!dfn[i]) {
				root = i, tarjan(i, -1);
			}
		}
		int ans = 0;
		for (int i = 1; i <= n; ++i) {
			if (isgd[i]) ++ans;
		}
		printf ("%d\n", ans);
		
	}
	return 0;
}

不同版本: 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 1e2 + 7;
const int M = 1e5 + 7;
int head[N], en;
struct Edge {
	int u, v, to;
} e[M];
void addedge(int u, int v) {
	e[++en].u = u;
	e[en].v = v;
	e[en].to = head[u];
	head[u] = en;
}
void init() {
	memset(head, -1, sizeof(head));
	en = 0;
}
namespace Tarjan {
	int dfn[N], low[N], isgd[N];
	int root = 0, deep = 0;
	void tarjan(int u) {
		
		low[u] = dfn[u] = ++deep;
		int child = 0;
		for (int i = head[u]; ~i; i = e[i].to) {
			int v = e[i].v;
			if (!dfn[v]) {
				tarjan(v);
				low[u] = min(low[u], low[v]);
				if (low[v] >= dfn[u]) {
					++child;
					if (u != root || child>= 2) isgd[u] = 1;
				}
			} else low[u] = min(low[u], dfn[v]);
		}
	}
}  using namespace Tarjan;

int main() {
	
	int n;
	while (~scanf ("%d", &n) && n) {
		
		int u, v;
		char ch;
		init();
		while (~scanf ("%d", &u) && u) {
			while (~scanf ("%d%c", &v, &ch)) {
				addedge(u, v);
				addedge(v, u);
				if (ch == '\n') break;
			}
		}
		memset(dfn, 0, sizeof(dfn));
		memset(low, 0, sizeof(low));
		memset(isgd, 0, sizeof(isgd));
		deep = 0;
		for (int i = 1; i <= n; ++i) {
			if (!dfn[i]) {
				//printf ("%d\n", i);
				root = i, tarjan(i);
			}
		}
		int ans = 0;
		for (int i = 1; i <= n; ++i) {
			if (isgd[i]) ++ans;
		}
		printf ("%d\n", ans);
	}
	return 0;
}

入门参考:

https://blog.csdn.net/qq_39670434/article/details/81570157

https://blog.csdn.net/u011815404/article/details/86703470

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值