【蓝桥杯】危险系数

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

struct node{
	int data;
	node *next;
};
node tab[1001];
int vis[1001] = { 0 };
int way[1001] = { 0 };
int count[1001] = { 0 };
int ans = 0;
void insert(int n, int x);
void init(int n);
void dfs(int x, int y, int step);
int fun(int n);

int main() {
	int x, y, n, m, u, v;
	scanf("%d%d", &n, &m);
	init(n);
	for(int i = 0; i < m; i++) {
		scanf("%d%d", &u, &v);
		insert(u, v);
		insert(v, u);
	}
	scanf("%d%d", &x, &y);
	dfs(x, y, 0);
	int ret = fun(n);
	printf("%d", ret);
	return 0; 
} 

void insert(int n, int x) {    //构造临接矩阵 
	node *p = &tab[n];         //取第n个点的地址 
	while(p->next != NULL) {   //把指针挪到链尾, 插入新的结点 
		p = p->next;
	}
	//构造新的结点并插入 
	node *num = new node;
	p->next = num;
	num->data = x;
	num->next = NULL; 
}

void init(int n) {                  //输入的初始化 
	for(int i = 1; i <= n; i++) {
		tab[i].data = i;
		tab[i].next = NULL;
	}
}

int fun(int n) {
	int res = 0;
	for(int i = 1; i <= n; i++) {
		if(count[i] == ans) {               //如果这个点的通过次数和x,y一样, 那么这个点破坏以后那条路一定被破坏 
			res++;                           
		}
	}
	return (res - 2);                       //去除x, y两个点 
}

void dfs(int x, int y, int step) {          //深搜从x到y的点 
	vis[x] = 1;                             //表示点x已经搜到 
	way[step] = x;                          //记录每一步走的哪个点 
	node *p = &tab[x];
	if(x == y) {                     
		ans++;                              //如果找到了x, 总数加1 
		for(int i = 0; i <= step; i++) {
			count[ way[i] ]++;              //则第way[i]个点的路过次数+1 
		}
		return;
	}
	while((p = p->next) != NULL) {        //当前数组元素的临界元素 没有遍历完 
		if( vis[p->data] != 1 ) {
			vis[p->data] = 1;             //走过的点进行标记 
			dfs(p->data, y, step + 1);    //深搜下一步 
			vis[p->data] = 0;             //清除标记 
		} 
	}
}


<think>嗯,用户问的是P8604 [蓝桥杯 2013 国 C] 危险系数这个问题,并且提到只能用暴力算法。我需要先理解题目要求,然后思考如何用暴力方法解决。 首先,题目大意是说,在无向图中,找出两点之间的所有路径,然后统计哪些节点在所有路径中都出现,这样的节点数就是危险系数。关键点是要找出所有必经节点。 暴力算法的话,应该怎么做呢?可能的步骤是: 1. 找出所有从u到v的路径。这可以通过深度优先搜索(DFS)或者广度优先搜索(BFS)实现,不过DFS可能更容易记录路径。 2. 统计每条路径上的节点。 3. 找出在所有路径中都出现的节点,这些节点的数量就是答案。但要注意排除起点和终点,因为题目中的危险系数计算是不包括它们的。 那具体怎么实现呢?比如,输入是多个点之间的边,需要构建邻接表。然后对每个可能的路径进行遍历,记录路径中的节点。之后统计每个节点在所有路径中出现的次数,如果次数等于总路径数,并且不是起点或终点,就计入危险系数。 但这里有个问题,如果图比较大,路径数量会指数级增长,暴力算法可能超时。不过题目是蓝桥杯的,可能数据规模不是特别大,允许用这种暴力方法。 那代码的大致思路是: - 读取输入,构建邻接表。 - 使用DFS遍历所有可能的路径,记录每条路径中的节点。 - 统计每个节点在多少条路径中出现过。 - 如果某个节点的出现次数等于总路径数,并且不是起点或终点,则危险系数加一。 需要注意避免重复访问节点,否则会陷入循环。比如在DFS过程中,需要记录已访问的节点,防止重复。 举个例子,比如输入是: 7 6 1 3 2 3 3 4 3 5 4 6 5 6 1 6 那正确的危险系数是2,因为节点3和4或3和5,但要看所有路径是否都经过某些节点。 那代码实现时,如何记录路径中的节点?可以用一个数组或者集合来保存当前路径中的节点,每找到一条路径,就将这些节点加入到一个字典或列表中,统计每个节点的出现次数。 具体步骤: 1. 输入顶点数n和边数m,然后输入m条边,构建邻接表。 2. 输入起点u和终点v。 3. 初始化一个计数器字典,保存每个节点的出现次数。 4. 使用DFS找所有u到v的路径,对于每条路径,将路径中的节点(除u和v外)在字典中计数加一。 5. 最后遍历字典,统计出现次数等于总路径数的节点数目。 但是,如何保证DFS不会因为环路而无限循环?比如,在DFS过程中,需要记录已访问的节点,避免重复访问。比如在递归的时候,维护一个visited集合,每次访问节点时标记为已访问,递归返回后取消标记。 例如,DFS函数参数可能包括当前节点、终点、路径列表、visited集合。每次访问一个节点时,添加到路径和visited中,然后遍历邻接节点,没访问过的就递归。当到达终点时,将路径中的节点统计到计数器中。 然后,总共有多少条路径?假设路径数可能很大,但蓝桥杯的数据可能允许。 然后,最后遍历计数器中的每个节点,如果出现次数等于路径总数,并且不是起点或终点,那么危险系数加一。 那代码的大致结构是: n, m = map(int, input().split()) edges = [[] for _ in range(n+1)] for _ in range(m): a, b = map(int, input().split()) edges[a].append(b) edges[b].append(a) u, v = map(int, input().split()) path_count = defaultdict(int) total_paths = 0 def dfs(current, visited, path): global total_paths visited.add(current) path.append(current) if current == v: total_paths += 1 for node in path[1:-1]: # 排除起点和终点 path_count[node] += 1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited.copy(), path.copy()) # 注意这里可能需要深拷贝 visited.remove(current) path.pop() dfs(u, set(), []) # 或者可能初始调用应该是 dfs(u, set([u]), [u]) ? 这里有一个问题,visited在递归调用时是否需要深拷贝。比如,在每次递归调用时,传递的是visited的拷贝,这样不同的路径分支不会互相干扰。例如,当前的递归函数中,当处理一个邻接点时,传递的是已访问的集合的拷贝,这样其他分支不会受到影响。否则,如果直接传递同一个集合,可能导致访问标记被错误共享。 比如,假设当前节点是A,邻接点是B和C。在处理B的时候,visited添加了B,然后递归进入B的处理。处理完B的分支后,回溯到A,此时visited中应该移除B,然后处理C的分支。但如果在递归调用时不进行拷贝,直接传递同一个集合,那么处理B时添加的B会被带到其他分支中,导致错误。比如,当处理完B的分支返回后,visited中移除了B,然后处理C的分支时,可以访问B吗?这取决于具体实现。所以,正确的做法是每次递归调用时,传递一个新的集合,包含之前已访问的节点加上当前节点,或者使用回溯法,在递归调用前添加,调用后移除。 或者,修改DFS函数,在进入节点时标记为已访问,递归结束后取消标记。这样可以避免深拷贝带来的性能问题。例如: def dfs(current, path): visited.add(current) path.append(current) if current == v: # 处理统计 pass else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, path) visited.remove(current) path.pop() 但这样,当在递归调用中修改同一个visited集合时,会导致不同路径之间互相影响。比如,在一条路径中访问了节点B,而另一条路径可能因为B已被标记而无法访问。因此,正确的做法应该是,在每次递归调用时,传递一个新的visited集合,或者在进入函数时标记,退出时取消,这样其他路径分支可以正确访问。 例如: def dfs(current, visited, path): new_visited = visited.copy() new_visited.add(current) new_path = path.copy() new_path.append(current) if current == v: global total_paths total_paths +=1 for node in new_path[1:-1]: path_count[node] +=1 return for neighbor in edges[current]: if neighbor not in new_visited: dfs(neighbor, new_visited, new_path) 这样,每次递归调用时,都会复制一份新的visited和path,这样不同路径之间不会互相干扰。但这样做可能会导致内存和性能问题,尤其是当路径很长时。不过对于题目中的小数据可能没问题。 或者,可以使用回溯的方法,即在递归调用前后添加和移除当前节点: def dfs(current, visited, path): visited.add(current) path.append(current) if current == v: # 统计路径中的节点 global total_paths total_paths +=1 for node in path[1:-1]: path_count[node] +=1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) visited.remove(current) path.pop() 但这里有一个问题,当递归返回时,path和visited会被修改,这样后面的循环中的其他邻接点会被正确处理吗?比如,假设当前节点A,邻接点是B和C。处理完B的分支后,visited中移除了B,然后处理C的时候,可以访问B吗?这显然是不正确的,因为在同一路径中,节点是不能重复访问的。但是,正确的DFS遍历路径的方式应该不允许重复访问节点,所以在递归时使用回溯的方式是正确的。因为,当处理B的时候,visited中添加了B,处理完B的分支后,移除B,这样在处理C的时候,B会被视为未被访问,从而允许其他路径可能包含B。这显然会导致错误,因为同一路径中的节点不能重复,但不同的路径可以包含相同的节点,比如不同的路径可能经过不同的顺序,但每个路径内部的节点是唯一的。哦,但是正确的路径定义是节点不重复的,所以每个路径中的节点必须是唯一的。因此,在递归过程中,使用回溯的方式是正确的,即每次进入节点时添加到visited,处理完所有邻接点之后,再移除,这样其他分支可以正确地访问该节点。 但这样的话,例如,在路径A→B→C→v时,visited中会有A、B、C。当返回到B,然后处理B的其他邻接点,假设还有D未被访问,那么路径A→B→D→v,此时D的递归调用中,visited包含A、B,进入D时添加D,然后继续。这样是正确的。 所以,正确的做法是使用回溯的方法,而不需要复制visited集合,这样效率更高,因为避免了大量的拷贝操作。 因此,初始调用应该是 dfs(u, set([u]), [u]),或者初始时visited是空,然后在函数内部添加current? 或者,在初始调用时,传递空的visited和空的path,然后在函数内部添加current? 比如,修改DFS函数: def dfs(current, visited, path): if current == v: # 处理统计 pass return for neighbor in edges[current]: if neighbor not in visited: new_visited = visited.copy() new_visited.add(neighbor) new_path = path.copy() new_path.append(neighbor) dfs(neighbor, new_visited, new_path) 这样,每次递归调用都会复制新的visited和path,这样可以避免回溯的问题,但效率可能较低。不过,对于蓝桥杯的题目来说,可能数据量不大,可以接受。 或者,另一种方式是: 在DFS函数中,每次访问一个节点时,将其加入visited和path,处理完所有邻接点后再弹出,这样不需要复制,效率更高。 例如: def dfs(node, target, visited, path, path_count, total_paths): visited.add(node) path.append(node) if node == target: total_paths[0] +=1 for n in path[1:-1]: path_count[n] +=1 else: for neighbor in edges[node]: if neighbor not in visited: dfs(neighbor, target, visited, path, path_count, total_paths) visited.remove(node) path.pop() 这样,使用回溯法,可以避免复制visited和path,提高效率。但是,在Python中,像total_paths这样的可变对象(比如用列表来保存计数)可以避免使用global声明。比如,将total_paths设置为一个列表,其中包含一个元素,这样在函数内部可以修改它。 现在,代码的结构大致是: n, m = map(int, input().split()) edges = [[] for _ in range(n+1)] for _ in range(m): a, b = map(int, input().split()) edges[a].append(b) edges[b].append(a) u, v = map(int, input().split()) path_count = defaultdict(int) total_paths = [0] def dfs(current, visited, path): visited.add(current) path.append(current) if current == v: total_paths[0] +=1 for node in path[1:-1]: # 排除起点和终点 path_count[node] +=1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) visited.remove(current) path.pop() dfs(u, set(), []) # 或者初始调用应该是 visited包含u吗? # 初始调用的时候,current是u,所以应该先将u加入visited和path? 哦,上面的初始调用可能有问题。比如,初始调用是dfs(u, set(), []), 但在函数内部,会先添加current到visited和path。所以第一次调用时,current是u,visited是空集合。函数内部会将u添加到visited,path添加u。这会导致正确吗? 是的。例如,初始调用dfs(u, visited, path)时,传入的是空集合和空列表。然后函数内部将current(u)加入visited,path添加u。然后处理邻接点。当递归返回时,visited会被移除u,path弹出u。这可能有问题,因为初始调用结束后,visited和path会被清空。但整个递归过程是正确的。 例如,假设u是起点,那么第一次调用时,current是u,visited是空,path是空。函数内将u加入visited和path。然后处理邻接点。例如,邻接点可能有3,那么进入3的处理,此时visited是{u}, path是 [u]。在处理3的时候,将其加入visited和path。当到达终点v时,统计path中的节点。 这可能正确。但初始调用可能应该将u作为参数传入,比如: visited = set() path = [] visited.add(u) path.append(u) 然后调用dfs(u, visited, path) 或者,在函数内部处理,初始调用时传入空集合和空列表,然后函数内部处理current节点。 不过,在初始调用时,正确的做法应该是: 调用dfs(u, visited, path),其中visited包含u,path包含u。或者,函数内部处理? 比如,修改初始调用为: visited = set() path = [] visited.add(u) path.append(u) dfs(u, visited, path) 或者,将函数内部修改为: def dfs(current, target, visited, path, path_count, total_paths): if current == target: # 处理统计 pass return for neighbor in edges[current]: if neighbor not in visited: visited.add(neighbor) path.append(neighbor) dfs(neighbor, target, visited, path, path_count, total_paths) visited.remove(neighbor) path.pop() 这样,初始调用时,visited包含u,path包含u。例如: visited = {u} path = [u] dfs(u, v, visited, path, path_count, total_paths) 这样可以确保在开始的时候,起点已经被正确加入。 可能我之前写的函数参数顺序有问题,导致初始调用不正确。这需要仔细检查代码逻辑。 总之,正确的步骤是: 1. 初始化邻接表。 2. 初始化path_count字典和total_paths计数器。 3. 使用DFS,从起点开始,记录所有到达终点的路径。 4. 对于每条路径,排除起点和终点,统计中间节点的出现次数。 5. 最后,统计出现次数等于总路径数的节点数目。 现在,编写代码时需要注意的问题: - 避免重复计算路径中的节点。 - 正确初始化visited和path。 - 在递归过程中正确处理回溯。 现在,考虑一个具体的例子,比如样例输入: 7 6 1 3 2 3 3 4 3 5 4 6 5 6 1 6 正确的危险系数是2。因为从1到6的路径可能有: 1-3-4-6 1-3-5-6 中间节点是3、4或3、5。所有路径都必须经过3,所以危险系数是1?或者可能还有其他路径? 或者,可能还有其他路径,比如: 1-3-2-3-4-6?但这样的话,路径中存在重复节点3,这不允许。因为题目中的路径应该是简单路径,即节点不重复。 所以,所有可能的路径必须是不重复节点的。 因此,在这个例子中,可能的路径是: 1-3-4-6 1-3-5-6 这两个路径,所以中间的节点3出现在所有路径中,而4和5各出现在一个路径中。所以危险系数是1? 但样例的输出是2。这说明我的理解可能有误,或者样例输入可能不同。 或者可能样例输入中的边是: 比如,另一组输入? 例如,题目给出的样例输入可能是: 7 6 1 3 2 3 3 4 3 5 4 6 5 6 然后查询的是1到6的危险系数? 此时,路径可能有: 1-3-4-6 1-3-5-6 所以危险系数是3?因为节点3、4、5都被部分路径包含?或者所有路径都经过的节点是3,所以危险系数是1? 但题目中的样例输出是2。可能我记错了。 或者,可能用户提供的题目描述中的测试案例可能有不同的情况。这里可能需要重新确认。 但回到问题,用户的问题是关于如何用暴力算法解决这个问题。因此,不管测试案例如何,只要正确实现上述逻辑即可。 现在,关于代码中的错误点: 在DFS的初始调用中,是否将起点加入visited和path? 例如,在函数中,应该一开始就将current加入visited和path吗? 比如,在函数内部,首先将current加入visited和path: def dfs(current, visited, path): visited.add(current) path.append(current) if current == v: # 统计 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) visited.remove(current) path.pop() 此时,初始调用应该是: visited = set() path = [] dfs(u, visited, path) 但是,这样在第一次调用时,current是u,函数内部将u加入visited和path。然后处理邻接点。这样是否正确? 是的。例如,假设u是1,v是6。初始调用时,visited是空集合,path是空列表。函数内部将current=1加入visited,path变为[1]。然后处理邻接点,比如3。进入递归调用dfs(3, visited, path)。此时,visited包含1,path是[1]。在函数内部,将3加入visited,path变为[1,3]。继续处理邻接点,比如1、4、5、2。但1已经在visited中,所以跳过。处理4时,加入path,以此类推,直到到达6。 当到达v时,将path中的节点(排除起点和终点)统计到path_count中。例如,路径1-3-4-6的中间节点是3、4。所以,path_count[3]和4各加一。另一条路径1-3-5-6的中间节点是3、5。所以,path_count[3]加一,5也加一。总共有两条路径。所以,3在两个路径中都被经过,所以出现次数是2。而4和5各出现一次。因此,危险系数是1(只有节点3的出现次数等于总路径数)。所以,输出是1?但可能题目中的样例输出不同。 但用户可能给出不同的测试案例。所以,关键在于正确实现算法。 综上,代码的大致结构应该是: 读取输入,构建邻接表,然后DFS找出所有路径,统计中间节点的出现次数,最后统计所有出现次数等于总路径数的节点数目,排除起点和终点。 现在,编写代码: 可能需要注意,在Python中,递归深度可能不够,如果路径较长,会触发最大递归深度错误。但对于蓝桥杯的题目,可能数据规模较小,不需要考虑这一点。 现在,代码的实现: n, m = map(int, input().split()) edges = [[] for _ in range(n+1)] for _ in range(m): a, b = map(int, input().split()) edges[a].append(b) edges[b].append(a) u, v = map(int, input().split()) from collections import defaultdict path_count = defaultdict(int) total_paths = 0 # 使用回溯法 def dfs(current, visited: set, path: list): global total_paths visited.add(current) path.append(current) if current == v: total_paths += 1 # 记录中间节点 for node in path[1:-1]: path_count[node] += 1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) # 回溯 visited.remove(current) path.pop() # 初始调用时,current是u,visited和path为空?或者应该初始时加入u? # 修改初始调用: # 因为第一次调用时,current是u,所以应该将u加入visited和path # 因此,在调用前,应该创建一个新的集合和列表,并添加u? # 正确的方式可能是,初始调用时,传入已包含u的visited和path: visited = set() path = [] dfs(u, visited, path) # 但是这样,在第一次调用时,current是u,函数内部会将u添加到visited和path。 # 但此时,visited和path在函数内部被修改,但初始时是空的。这样,第一次调用时,函数内部的visited和path会被添加u,之后递归处理。 # 这样是否正确? 比如,当调用dfs(u, visited, path)时,其中visited和path初始为空。在函数内部,current是u,被添加到visited和path中。然后处理邻接点。这样是否正确? 是的。例如,第一次调用时,current是u,那么: visited.add(current) → visited现在是 {u} path.append(current) → path is [u] 然后,处理邻接点。例如,邻接点3。检查3是否在visited → 不在,所以递归调用dfs(3, visited, path)。 此时,visited是 {u},传入到函数中的参数是 visited(此时是 {u})和 path(此时是 [u]). 在递归调用中,current是3,添加到visited → {u,3}, path变成 [u,3]. 以此类推,直到找到v。当找到v时,统计中间节点。 当递归返回时,visited.remove(current) → 比如,在处理完3之后,回到u的循环,此时visited是 {u}, path是 [u]. 这样是正确的。 因此,初始调用应该是 dfs(u, set(), []). 但这样,在函数内部,第一次调用时,current是u,被加入visited和path,从而开始正确的递归。 现在,测试这个代码是否正确? 假设输入为: 7 6 1 3 2 3 3 4 3 5 4 6 5 6 1 6 那u=1,v=6。可能的路径是: 1-3-4-6 → 中间节点3,4 1-3-5-6 → 中间节点3,5 所以,总共有两条路径。path_count中,3出现2次,4和5各出现一次。所以,只有节点3的出现次数等于总路径数(2)。所以危险系数是1。 但根据用户的问题,可能样例的输出是2,所以可能我的测试案例不正确。或者,原题的样例可能不同。 可能我之前提到的测试案例不是正确的题目样例。所以,代码的正确性应该由算法是否能够正确统计所有必经节点来判断。 现在,假设代码正确,那么危险系数的计算方式是正确的。 最后,统计所有在path_count中出现次数等于总路径数的节点数目,并排除u和v。 例如: result = 0 for node in path_count: if node == u or node == v: continue if path_count[node] == total_paths: result +=1 print(result) 这样,如果total_paths是0,说明u和v不连通,此时输出0?根据题目描述,如果u和v不连通,危险系数是0吗? 是的。例如,当u无法到达v时,中间没有路径,所以危险系数是0。 综上,最终的代码应该包含这些逻辑。 现在,将代码整合: n, m = map(int, input().split()) edges = [[] for _ in range(n+1)] for _ in range(m): a, b = map(int, input().split()) edges[a].append(b) edges[b].append(a) u, v = map(int, input().split()) from collections import defaultdict path_count = defaultdict(int) total_paths = 0 def dfs(current, visited, path): global total_paths visited.add(current) path.append(current) if current == v: total_paths += 1 # 排除起点和终点 for node in path[1:-1]: path_count[node] += 1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) # 回溯 visited.remove(current) path.pop() # 初始调用 dfs(u, set(), []) result = 0 for node in path_count: if node == u or node == v: continue if path_count[node] == total_paths: result += 1 print(result) 但这里有个问题,初始调用时,visited是空集合,path是空列表。当函数内部第一次将current(u)添加到visited和path,此时visited和path被修改。但是,当递归返回时,visited会被移除u,path会被弹出u。这样,当整个DFS结束时,visited和path又回到初始状态,空集合和空列表。这不会影响结果,因为统计已经完成。 现在,测试这个代码是否正确。假设测试案例中的危险系数是2,那可能需要检查代码是否有错误。 例如,假设另一个测试案例: 输入: 4 3 1 2 2 3 3 4 1 4 那么,从1到4的路径只有一条:1-2-3-4。中间节点是2和3。所以危险系数是2。此时,总路径数是1。所以path_count中的2和3各出现一次。所以结果应该是2。代码应该输出2。 测试代码是否能够处理这样的情况。 在代码中,当执行dfs(1, set(), []). 函数调用时,current是1,添加到visited和path。然后处理邻接点2。 调用dfs(2, {1}, [1]). 这时,current是2,添加到visited→{1,2}, path→[1,2]. 处理邻接点1(在visited中,跳过)、3(未在visited中)。 调用dfs(3, {1,2}, [1,2]). 此时current是3,添加到visited→{1,2,3}, path→[1,2,3]. 处理邻接点2(在visited中)、4(未在visited中)。 调用dfs(4, {1,2,3}, [1,2,3]). current是4,等于v。此时,total_paths加一。中间节点是2和3,所以path_count[2]和3各加一。 回溯后,返回处理3的其他邻接点,没有其他,回到2。然后处理2的其他邻接点,没有。回到1。此时,所有路径处理完毕。total_paths是1。path_count中,2和3各出现1次。所以,结果应该是2。代码输出正确。 这说明代码是正确的。 那回到原来的问题,用户提到的题目是否可能正确? 是的。因此,这个暴力算法是正确的,通过DFS找出所有路径,统计中间节点的出现次数,最后判断哪些节点在所有路径中出现。</think><< [蓝桥杯 2013 国 C] 危险系数的暴力算法实现思路如下: ### 核心思路 1. **构建邻接表**:存储图的连接关系 2. **DFS 遍历所有路径**:使用深度优先搜索找到所有从起点到终点的路径 3. **统计必经节点**:记录每个节点在所有路径中出现的次数,最终统计出现次数等于总路径数的节点 ### 代码实现 ```python n, m = map(int, input().split()) edges = [[] for _ in range(n + 1)] for _ in range(m): a, b = map(int, input().split()) edges[a].append(b) edges[b].append(a) u, v = map(int, input().split()) from collections import defaultdict path_count = defaultdict(int) total_paths = 0 def dfs(current, visited, path): global total_paths visited.add(current) path.append(current) if current == v: total_paths += 1 # 统计中间节点(排除首尾) for node in path[1:-1]: path_count[node] += 1 else: for neighbor in edges[current]: if neighbor not in visited: dfs(neighbor, visited, path) # 回溯 visited.remove(current) path.pop() # 初始调用(注意参数传递方式) dfs(u, set(), []) # 计算结果 result = 0 for node in path_count: if node == u or node == v: continue if path_count[node] == total_paths: result += 1 print(result) ``` ### 关键点解释 1. **DFS 回溯机制**:通过 `visited` 集合和 `path` 列表的增删操作实现路径探索,避免循环访问 2. **必经节点判断**:节点出现次数等于总路径数时即为关键节点 3. **时间复杂度**:暴力枚举所有路径,复杂度为 O(N!),适合小规模数据 4. **空间优化**:使用回溯法减少内存拷贝,直接操作集合和列表 ### 特殊处理 - 若起点和终点不连通,直接输出 0 - 路径统计时排除首尾节点 - 使用全局变量统计总路径数和节点出现次数 >>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值