hdu3671 Boonie and Clyde Tarjan求割点

Boonie and Clyde

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 773    Accepted Submission(s): 221


Problem Description
As two icons of the Great Depression, Bonnie and Clyde represent the ultimate criminal couple. Stories were written, headlines captured, and films were made about the two bank robbers known as Romeo and Juliet in a getaway car.

The new generation of Bonnie and Clyde is no longer cold-blooded killers with guns. Due to the boom of internet, they turn to online banks and scheme to hack the safety system. The safety system consists of a number of computers connected by bidirectional cables. Since time is limited, they decide that they will attack exactly two computers A and B in the network, and as a result, other computers won't be able to transmit messages via A and B . The attack is considered successful if there are at least two computers (other than A and B ) that disconnected after the attack.

As they want to minimize the risk of being captured, they need to find the easiest way to destroy the safety system. However, a brief study of the network indicates that there are many ways to achieve their objective; therefore they kidnapped the computer expert, you, to help with the calculation. To simplify the problem, you are only asked to tell them how many ways there are to destroy the safety system.
 

Input
There are multiple test cases in the input file. Each test case starts with two integers N (3<=N<=1000) and M (0<=M<=10000) , followed by M lines describing the connections between the N computers. Each line contains two integers A , B (1<=A, B<=N) , which indicates that computer A and B are connected by a bidirectional cable.

There is a blank line between two successive test cases. A single line with N = 0 and M = 0 indicates the end of input file.
 

Output
For each test case, output one integer number representing the ways to destroy the safety system in the format as indicated in the sample output.
 

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

Sample Output
  
Case 1: 2 Case 2: 11
 

Source
 


思路:http://blog.youkuaiyun.com/zjtzyrc/article/details/49075923


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int N, M, C;
vector<int> G[1000 + 5];
//rem为删掉的第一个点,index用于给节点打时间戳,cnt存一个连通分支内的节点数量
//ans为割点数目
int rem, index, len, ans, root, num[1000 + 5], cnt[1000 + 5], low[1000 + 5], p[1000 + 5];

int tarjan(int v) {
	low[v] = num[v] = ++index;
	int ret = 1, sons = 0;
	for (int i = 0; i < G[v].size(); i++) {
		int w = G[v][i];
		if (w == rem) {  //排除第一个删除的点
			continue;
		}
		if (!num[w]) {
			p[w] = v;
			sons++;
			ret += tarjan(w);
			if (low[w] >= num[v] && v != root) {
				ans++;
			}
			low[v] = min(low[v], low[w]);
		}
		else if (p[v] != w){
			low[v] = min(low[v], num[w]);
		}
	}
	if (sons >= 2 && v == root) {
		ans++;
	}
	return ret;
}

int main()
{
	C = 0;
	while (~scanf("%d%d", &N, &M) && (N || M)) {
		for (int i = 0; i <= N + 3; i++) {
			G[i].clear();
		}
		for (int i = 0; i < M; i++) {
			int u, v;
			scanf("%d%d", &u, &v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		int res = 0;
		for (int i = 1; i <= N; i++) {  //遍历每一个点
			memset(num, 0, sizeof(num));
			rem = i; index = 0; len = 0; ans = 0;
			for (int j = 1; j <= N; j++) {  //遍历其他非rem的点
				if (j != rem && !num[j]) {  //num[j]为0说明这个连通分支还没算过
					root = j;
					cnt[len++] = tarjan(root);  //len为去掉rem后连通分支数
				}
			}
			if (len >= 3) {  //删掉rem后,原图分为三块或三块以上
				res += N - 1;  //任意找个第二个点都满足
			}
			else if (len == 2) {  //删掉rem后,原图分为两块
				res += N - 1;
				if (cnt[0] == 1) {  //如果其中有一块只有一个节点,情况要减一
					res--;
				}
				if (cnt[1] == 1) {
					res--;
				}
			}
			else if (len == 1) {
				res += ans;  //删掉rem后,原图还是一块(说明删掉的rem不是原图割点,上面两个其实删掉的都是割点)
			}
		}
		printf("Case %d: %d\n", ++C, res / 2);  //res中每种情况算了两边,要除以二
	}
	return 0;
}


### 使用Tarjan算法计算强连通分量数量 #### 算法原理 Tarjan算法通过深度优先搜索(DFS)遍历有向图中的节,记录访问顺序和低链值(low-link value),从而识别出所有的强连通分量。当发现一个节的访问序号等于其最低可达节编号时,表明找到了一个新的强连通分量。 #### 时间复杂度分析 该方法的时间效率取决于存储结构的选择。对于采用邻接表表示的稀疏图而言,整体性能更优,能够在线性时间内完成操作,即O(n+m)[^4];而针对稠密图则可能退化至平方级别(O(n²))。 #### Python代码实现 下面给出一段Python程序用于演示如何基于NetworkX库构建并处理带权无环图(DAG),进而解其中存在的全部SCC及其总数: ```python import networkx as nx def tarjan_scc(graph): index_counter = [0] stack = [] lowlinks = {} index = {} result = [] def strongconnect(node): # Set the depth index for this node to be the next available incrementing counter. index[node] = index_counter[0] lowlinks[node] = index_counter[0] index_counter[0] += 1 stack.append(node) try: successors = graph.successors(node) except AttributeError: successors = graph.neighbors(node) for successor in successors: if successor not in lowlinks: strongconnect(successor) lowlinks[node] = min(lowlinks[node], lowlinks[successor]) elif successor in stack: lowlinks[node] = min(lowlinks[node], index[successor]) if lowlinks[node] == index[node]: scc = set() while True: current_node = stack.pop() scc.add(current_node) if current_node == node: break result.append(scc) for node in graph.nodes(): if node not in lowlinks: strongconnect(node) return result if __name__ == "__main__": G = nx.DiGraph() # Create a directed graph object using NetworkX library edges_list = [(1, 2),(2, 3),(3, 1)] # Define edge list according to sample input data from hdu1269 problem statement[^5] G.add_edges_from(edges_list) components = tarjan_scc(G) print(f"Number of Strongly Connected Components found: {len(components)}") ``` 此段脚本定义了一个名为`tarjan_scc()`的功能函数接收网络对象作为参数,并返回由集合组成的列表形式的结果集,每个子集中包含了构成单个SCC的所有顶。最后部分展示了创建测试用DAG实例的过程以及调用上述功能获取最终答案的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值