求简单无向图中环的个数

Question

D. A Simple Task
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no repeated vertices or edges.

Input

The first line of input contains two integers n and m (1 ≤ n ≤ 190 ≤ m) – respectively the number of vertices and edges of the graph. Each of the subsequent m lines contains two integers a and b, (1 ≤ a, b ≤ na ≠ b) indicating that vertices a and b are connected by an undirected edge. There is no more than one edge connecting any pair of vertices.

Output

Output the number of cycles in the given graph.

Sample test(s)
input
4 6
1 2
1 3
1 4
2 3
2 4
3 4
output
7
Note

The example graph is a clique and contains four cycles of length 3 and three cycles of length 4.

求简单无向图中环的个数?简单无向图即 无自环,无重边的无向图。

 这个是NP问题; codeforces 上有一题用的是状态压缩写的。

 dp[s][i] s集合里最小的点到其他点的路径数;

dp[s][i] += dp[s^(1<<i)][j](g[j][i]=true)

ans加上可以构成环的路径数.怎么才能构成环呢? 如a->b->.....->c ,如果知道ac是可达的,只要加上a,经过ab...到达c的路径数就可以了。注意a是这个集合里最小的数。而且同一个环会被记录两次,因为2条路径才是一个环。

codeforces 11D  http://www.codeforces.com/contest/11/problem/D


code :

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

typedef __int64 ll;
#define maxn 20
ll dp[1<<maxn][maxn]; // 注意数据
bool g[maxn][maxn];
// dp[s][i] s中最小的点到其他点路径数;
// dp[s][i] += dp[s^i][j](g[i][j] = true )

int main(){
    int n, m;
    while( cin >> n >> m ) {
        memset(g, 0, sizeof g);
        int state = (1<<n);
        for ( int i=0; i<state; ++i)
          for ( int j=0; j<n; ++j )
            dp[i][j] = 0;

        for ( int i=0, a, b; i<m; ++i ){
            scanf ("%d%d", &a, &b);
            --a, --b;
            g[a][b] = g[b][a] = true;
            dp[(1<<a)|(1<<b)][a] = dp[(1<<a)|(1<<b)][b] = 1;
        }

        ll ans = 0;
        for ( int s=1; s<state; ++s ){
             int i, j, k;
             for ( i=0; i<n && !(s&(1<<i)); ++i );
             for ( j=i+1; j<n; ++j ) if(s&(1<<j) )
             {
                 for ( k=i+1; k<n; ++k ) if(s&(1<<k)){
                      if(g[k][j] )
                        dp[s][j] += dp[s^(1<<j)][k];
                 }
                 if(g[i][j] && (s^(1<<i)^(1<<j))) // 3个点以上才行
                   ans += dp[s][j];
             }
        }
        // 枚举了环的两侧,so。。。
        cout << (ans>>1) << endl;
    }
};

转载地址:

http://www.cnblogs.com/TengXunGuanFangBlog/archive/2013/04/19/loop_problem.html

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: ```python class Tarjan: def __init__(self, graph): self.graph = graph self.index = 0 self.stack = [] self.visited = [False for _ in range(graph.num_vertices)] self.indices = [-1 for _ in range(graph.num_vertices)] self.low_link_values = [-1 for _ in range(graph.num_vertices)] self.on_stack = [False for _ in range(graph.num_vertices)] self.scc = [] def is_cyclic(self): for vertex in range(self.graph.num_vertices): if not self.visited[vertex]: self.strongconnect(vertex) return any(len(x) > 1 for x in self.scc) def strongconnect(self, vertex): self.visited[vertex] = True self.indices[vertex] = self.index self.low_link_values[vertex] = self.index self.index += 1 self.stack.append(vertex) self.on_stack[vertex] = True for neighbor in self.graph.get_adjacent_vertices(vertex): if not self.visited[neighbor]: self.strongconnect(neighbor) self.low_link_values[vertex] = min(self.low_link_values[vertex], self.low_link_values[neighbor]) elif self.on_stack[neighbor]: self.low_link_values[vertex] = min(self.low_link_values[vertex], self.indices[neighbor]) if self.low_link_values[vertex] == self.indices[vertex]: scc = set() while True: w = self.stack.pop() self.on_stack[w] = False scc.add(w) if w == vertex: break self.scc.append(scc) ``` 上面是Tarjan算法查找无向图中环的Python代码。使用时,需要传入一个图对象,然后调用is_cyclic()方法,如果返回值为True,则说明图中存在。 注意,这段代码需要图数据结构的支持,图的实现可以自己实现或者使用第三方库如networkx。 ### 回答2: Tarjan算法是一种强连通分量算法,可以用于在无向图中查找。下面是用Python实现Tarjan算法的代码: ```python class Graph: def __init__(self, num_vertices): self.num_vertices = num_vertices self.adj_list = [[] for _ in range(num_vertices)] self.visited = [False] * num_vertices self.low = [0] * num_vertices self.ids = [0] * num_vertices self.id = 0 self.result = [] def add_edge(self, u, v): self.adj_list[u].append(v) self.adj_list[v].append(u) def tarjan(self, v, parent): self.visited[v] = True self.low[v] = self.ids[v] = self.id self.id += 1 for neighbor in self.adj_list[v]: if neighbor == parent: continue if not self.visited[neighbor]: self.tarjan(neighbor, v) self.low[v] = min(self.low[neighbor], self.low[v]) if self.low[neighbor] > self.ids[v]: self.result.append((v, neighbor)) else: self.low[v] = min(self.low[v], self.ids[neighbor]) def find_cycles(self): for i in range(self.num_vertices): if not self.visited[i]: self.tarjan(i, -1) if len(self.result) == 0: print('The graph does not contain any cycles.') else: print('The cycles in the graph are:') for cycle in self.result: print(cycle) g = Graph(5) g.add_edge(0, 1) g.add_edge(1, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.find_cycles() ``` 以上代码实现了一个`Graph`类,包含了添加边、Tarjan算法等功能。通过调用`find_cycles`方法可以找到给定无向图中的所有。在测试代码中,创建了一个包含5个顶点的无向图,并添加了若干条边。通过调用`find_cycles`方法,将打印出图中的所有。如果图中不包含任何,则会打印出相应的提示信息。 ### 回答3: Tarjan算法是一种用于查找无向图中环的强大算法。它通过遍历图中的每个节点,深度优先搜索子节点,并利用栈来维护当前遍历路径的节点。具体的Python实现如下: ```python class Graph: def __init__(self, vertices): self.V = vertices self.adj = [[] for _ in range(vertices)] self.Index = [-1] * vertices self.Lowlink = [-1] * vertices self.OnStack = [False] * vertices self.stack = [] self.count = 0 def addEdge(self, u, v): self.adj[u].append(v) self.adj[v].append(u) def tarjan(self, u, parent): self.Index[u] = self.count self.Lowlink[u] = self.count self.count += 1 self.stack.append(u) self.OnStack[u] = True for v in self.adj[u]: if v == parent: continue if self.Index[v] == -1: self.tarjan(v, u) self.Lowlink[u] = min(self.Lowlink[u], self.Lowlink[v]) elif self.OnStack[v]: self.Lowlink[u] = min(self.Lowlink[u], self.Index[v]) if self.Lowlink[u] == self.Index[u]: w = -1 while w != u: w = self.stack.pop() self.OnStack[w] = False print(w, end=" ") print() def findCycle(self): for i in range(self.V): if self.Index[i] == -1: self.tarjan(i, -1) # 测试样例 g = Graph(5) g.addEdge(1, 0) g.addEdge(0, 2) g.addEdge(2, 1) g.addEdge(0, 3) g.addEdge(3, 4) print("无向图中的为:") g.findCycle() ``` 这段代码首先定义了一个Graph类来表示无向图,其中包括图的顶点数和邻接列表。在tarjan函数中,使用了Index、Lowlink和OnStack列表来记录每个节点的索引、最低链接值以及是否在栈中。遍历节点时,使用递归进行深度优先搜索,并根据Index和Lowlink值来判断是否找到。在findCycle函数中,遍历图中的每个节点,对没有被访问过的节点调用tarjan函数进行的查找。最后的测试样例中,创建了一幅无向图,然后调用findCycle函数查找,并输出结果。 希望这段代码能够帮助你理解Python实现的Tarjan算法,并在无向图中查找的过程中能够起到指导作用。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值