图中的最长环

Posted 929code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图中的最长环相关的知识,希望对你有一定的参考价值。

给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,其中每个节点 至多 有一条出边。
图用一个大小为 n 下标从 0 开始的数组 edges 表示,节点 i 到节点 edges[i] 之间有一条有向边。
如果节点 i 没有出边,那么 edges[i] == -1 。

1. 深度优先搜索

同时记录已遍历的进行剪枝

class Solution 
public:
    int longestCycle(vector<int>& edges) 
        int res = -1;
        int n = edges.size();
        vector<int> pathval(n);
        for(int i=0;i<n;i++)//遍历所有节点找环
            if(edges[i]<0) continue;//没有出边,或已经遍历过
            int cur = i; int val = 1;
            vector<int> visit;
            while(cur>=0)//递归到没有下一个顶点
                visit.push_back(cur);//加入已遍历节点中
                if(edges[cur]<0) break;//下一节点已遍历,跳出循环,剪枝
                if(pathval[cur]>0)
                    res = max(res,val-pathval[cur]);//计算环的长度
                    break;//这次循环遍历过
                
                pathval[cur] = val;//顶点赋权值
                val++;//权值增加
                cur= edges[cur];//移动到下一节点
            
            for(int index:visit)
                edges[index] = -1;//将已遍历的置为-1
        
        return res;
    
;

2. 更优雅的写法

运用全局时间戳,减少判断

class Solution 
public:
    int longestCycle(vector<int> &edges) 
        int n = edges.size();
        int res = -1;
        vector<int> time(n);
        for (int i = 0, clock = 1; i < n; i++) //遍历n个顶点
            if (time[i]) continue; //已经遍历过跳过
            for (int x = i, start_time = clock; x >= 0; x = edges[x]) //递归到没有下一个顶点
                if (time[x])  // 重复访问
                    if (time[x] >= start_time) // 找到了一个新的环,关键语句,全局时间戳,避免将原来遍历过的视为环
                        res = max(res, clock - time[x]);
                    break;
                
                time[x] = clock++;//标记
            
        
        return res;
    
;

hdu4514(非连通图的环判断与图中最长链)(树的直径)

湫湫系列故事——设计风景线

随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好。 
  现在已经勘探确定了n个位置可以用来建设,在它们之间也勘探确定了m条可以设计的路线以及他们的长度。请问是否能够建成环形的风景线?如果不能,风景线最长能够达到多少? 
  其中,可以兴建的路线均是双向的,他们之间的长度均大于0。 

Input  测试数据有多组,每组测试数据的第一行有两个数字n, m,其含义参见题目描述; 
  接下去m行,每行3个数字u v w,分别代表这条线路的起点,终点和长度。 

   [Technical Specification] 
  1. n<=100000 
  2. m <= 1000000 
  3. 1<= u, v <= n 
  4. w <= 1000 
Output  对于每组测试数据,如果能够建成环形(并不需要连接上去全部的风景点),那么输出YES,否则输出最长的长度,每组数据输出一行。 
Sample Input

3 3
1 2 1
2 3 1
3 1 1

Sample Output

YES

题解:就是判环,如果无环的话就求出树的直径,如果有环的话就输出YES,就可以了,记录一个最
长路,和次长路,就ok了。
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #define N 100007
 8 #define M 1000007
 9 using namespace std;
10 
11 int n,m,ans;
12 int cnt,head[N],Next[M*2],rea[M*2],val[M*2];
13 int f[N][3],fa[N];
14 bool vis[N];
15 
16 void Add(int u,int v,int fee){Next[++cnt]=head[u],head[u]=cnt,rea[cnt]=v,val[cnt]=fee;}
17 int find(int num)
18 {
19     if (fa[num]!=num) return fa[num]=find(fa[num]);
20     return fa[num];
21 }
22 void dfs_solve(int u,int fa)
23 {
24     for (int i=head[u];i!=-1;i=Next[i])
25     {
26         int v=rea[i],fee=val[i];
27         if (v==fa||vis[v]) continue;
28         vis[v]=1;dfs_solve(v,u);
29         if (f[v][1]+fee>f[u][1])
30         {
31             f[u][2]=f[u][1];
32             f[u][1]=f[v][1]+fee;
33         }
34         else if (f[v][1]+fee>f[u][2]) f[u][2]=f[v][1]+fee;
35     }
36     ans=max(ans,f[u][1]+f[u][2]);
37 }
38 int main()
39 {
40     while (~scanf("%d%d",&n,&m))
41     {
42         ans=cnt=0;
43         bool flag=0;
44         memset(vis,0,sizeof(vis));
45         memset(head,-1,sizeof(head));
46         memset(f,0,sizeof(f));
47         for (int i=1;i<=n;i++) fa[i]=i;
48         for (int i=1,x,y,z;i<=m;i++)
49         {
50             scanf("%d%d%d",&x,&y,&z);
51             if (flag) continue;
52             int u=find(x),v=find(y);
53             if (u==v)
54             {
55                 flag=1;
56                 printf("YES\n");
57             }
58             else fa[u]=v;
59             Add(x,y,z),Add(y,x,z);
60         }
61         if (flag) continue;
62         ans=-1;
63         for (int i=1;i<=n;i++)
64         {
65             if (!vis[i])
66             {
67                 vis[i]=1;
68                 dfs_solve(i,-1);
69             }
70         }
71         printf("%d\n",ans);
72     }
73 }

 

以上是关于图中的最长环的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)

1205B Shortest Cycle(floyd找最小环)

有向无环图中的最小路径覆盖

检查有向无环图中两个顶点之间是不是存在路径 - 查询

在有向无环图中找到最低共同祖先的算法?

leetcode中等2192有向无环图中一个节点的所有祖先