无向图中环的问题

求简单无向图中环的个数?

简单无向图即 无自环,无重边的无向图。

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

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

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

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

#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;
    }
};
求最小环路径,任意一条最小环的路径。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

#define maxn 108
int n, m;
int dist[maxn][maxn], g[maxn][maxn];
int pre[maxn][maxn]; // 路径
#define INF 1<<24
vector<int > ans;

void init(){
    for(int i=1; i<=n; ++i)
      for(int j=1; j<=n; ++j)
      dist[i][j]=g[i][j]=INF, pre[i][j]=i;
    int u, v, w;
    for(int i=0; i<m; ++i ) {
        scanf("%d%d%d", &u, &v, &w);
        if(w < dist[u][v] ){
           dist[u][v] = dist[v][u] = w;
           g[u][v] = g[v][u] = w;
        }
    }
};


void solve(){
    int minn = INF;  ans.clear();
    for(int k=1; k<=n; ++k )
    {
       // 枚举两条边,点号小于k
        for(int i=1; i<k; ++i) if(g[i][k]^INF)
          for(int j=i+1; j<k; ++j) if(g[k][j]^INF && dist[i][j]^INF) {
              int tmp = dist[i][j]+g[i][k]+g[k][j];
              if(tmp < minn) { // 求出路径
                   minn = tmp;  ans.clear();
                   int p = j;
                   while(p != i) {
                        ans.push_back(p);
                        p = pre[i][p];
                   }
                   ans.push_back(i);
                   ans.push_back(k);
              }
          }

        for(int i=1; i<=n; ++i ) if(dist[i][k]^INF)
          for(int j=1; j<=n; ++j )if(dist[k][j]^INF) {
              int tmp = dist[i][k]+dist[k][j];
              if(tmp < dist[i][j]) {
                  dist[i][j]= tmp;
                  pre[i][j] = pre[k][j]; // 从后往前
              }
          }
    }

    if(minn ^ INF) {
        //cout<< minn << endl;
         for(int i=0; i<ans.size(); ++i){
           if(i) printf(" ");  printf("%d", ans[i]);
         }
         puts("");
         return ;
    }
    puts("No solution.");
};

int main(){
    while(~scanf("%d%d", &n, &m)){
      init();
      solve();
    }
};
求最大环路径,任意一条最大环的路径。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxm = 100005;
const int maxn = 27*27;
int n, head[maxn], e, N;
struct Edge{
    int u, v, next; double w;
    Edge(){}
    Edge(int U, int V, int Ne, double W):
         u(U), v(V), next(Ne), w(W){}
}edge[maxm];

void add(int u, int v, double w){
   edge[e] = Edge(u, v, head[u], w); head[u] = e++;
}

int mm[30][30];

int get( char x, char y) {
    int i = x-'a', j = y-'a';
    if(mm[i][j] == 0) mm[i][j]=++N;
    return mm[i][j];
}

double maxLength;

void init(){
     char str[1071];
     e = 0;   N = 0; maxLength = 0; //maxLength 最大的边
     memset(head, -1, sizeof head); //开始这里我用的是fill,悲剧的rt了如干次啊
     memset(mm, 0, sizeof mm);

     getchar();
     for(int i=0; i<n; ++i ) {
         scanf("%s", str);
         int sz = strlen(str);
         if(sz < 3) continue;
         int u = get(str[0], str[1]);
         int v = get(str[sz-2], str[sz-1]);
         add(u, v, sz); //每个字串见条边就可以了
         if(sz > maxLength) maxLength = sz;
     }
}

double dist[maxn];
int cnt[maxn];
bool vis[maxn];
int Q[maxn];

bool spfa( double x ) {
    fill(dist+1, dist+1+N, 0);
    fill(cnt+1, cnt+1+N, 0 );
    memset(vis, 0, sizeof vis);
    int l=0, r=0;
    for(int i=1; i<=N; ++i)
      Q[r++] = i, vis[i]=1;
    while(l != r) {
         int u = Q[l++]; if(l == maxn) l=0;  vis[u]=0;
         for ( int i=head[u]; ~i; i=edge[i].next){
             int v = edge[i].v; double w =  edge[i].w;
             if(dist[u]+w-x > dist[v]){
                  dist[v] = dist[u]+w-x;
                  if(vis[v] ) continue;
                  Q[r++] = v; vis[v]=1;
                  if(r == maxn) r=0;
                  if(++cnt[v] > N) return 1; // 存在正环
             }
         }
    }
    return 0;
}

#define eps 1e-4
void solve()
{
    double l = 0, r = maxLength, mid, ans=-1;
    while(r-l >= eps){// 二分球结果
         mid = (l+r)/2.0;
         if(spfa( mid )  ) {
              ans = mid;
              l = mid;
         }else r = mid;
    }
    if(ans > eps) printf("%.2lf\n", ans);
    else puts("No solution.");
};


int main(){
     while( scanf("%d", &n), n ){
         init();
         solve();
     }
}

转载自:https://www.cnblogs.com/TengXunGuanFangBlog/archive/2013/04/19/loop_problem.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答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算法,并在无向图中查找环的过程中能够起到指导作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值