【问题标题】:how to find whether a graph is tree or not?如何判断一个图是否是树?
【发布时间】:2014-08-11 00:32:05
【问题描述】:

我正在尝试解决一个 SPOJ 问题is it a tree ?,在该问题中我必须检查一个图是否是树? 在这个问题中,我使用 DFS 来检测图形是否有循环..

我的代码是..

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <string.h>

using namespace std;

typedef long long int64;
typedef unsigned long long uint64;
#define two(X) (1<<(X))
#define twoL(X) (((int64)(1))<<(X))
#define contain(S,X) (((S)&two(X))!=0)
#define containL(S,X) (((S)&twoL(X))!=0)
const double pi=acos(-1.0);
const double eps=1e-11;
template<class T> inline void checkmin(T &a,T b){if(b<a) a=b;}
template<class T> inline void checkmax(T &a,T b){if(b>a) a=b;}
template<class T> inline T sqr(T x){return x*x;}
typedef pair<int,int> ipair;
#define SIZE(A) ((int)A.size())
#define LENGTH(A) ((int)A.length())
#define MP(A,B) make_pair(A,B)
#define PB(X) push_back(X)
int scanInt()
{
    char c;
    int ans=0;
    while(true)
    {
        c=getchar_unlocked();
        if(c==' ' || c=='\n')
            return ans;
        ans=(ans<<3)+(ans<<1)+c-'0';
    }
}
bool applyDFS(vector<vector<int> > &graph,int n)
{
    queue <int> st;
    int i,j=0;
    vector<bool> visited(n+1,false);
    int node=1;
    st.push(1);
    while(!st.empty())
    {
        node=st.front();
        st.pop();
        if(visited[node])
           {
            return false;
            }
            visited[node]=true;
        for(i=0;i<graph[node].size();i++)
            {
                if(!visited[graph[node][i]])
                    st.push(graph[node][i]);
            }
        j++;
    }
    return j==n?true:false;
}
int main()
{
    int n,m,x,y,i;
    //freopen("input.txt","r",stdin);
    n=scanInt();
    m=scanInt();
       vector <vector<int> > graph(n+1);
       stack <int > st;
    for(i=0;i<m;i++)
    {
          x=scanInt();
          y=scanInt();
          graph[x].PB(y);
          graph[y].PB(x);
          st.push(x);
    }
    if(applyDFS(graph,n))
        cout<<"YES\n";
    else
        cout<<"NO\n";
    return 0;
}

当我提交解决方案时,我收到“超出时间限制”消息。有没有更好的方法来解决这个问题??

【问题讨论】:

  • 您无需尝试寻找周期。想想一棵树的属性,最重要的是,它有多少个组件?它有多少条边?
  • @kevmo314 你可以有一个包含 3 个节点和 2 条边的图,它不是一棵树(它包含一个循环)。所以这绝对是一个“如果”,而不是“仅当”
  • @alfasin 您的图表有两个组件。
  • @alfasin 好吧,我想避免直接给出答案,但是树是具有一个组件和 V-1 边的图。参见:en.wikipedia.org/wiki/Tree_(graph_theory),即“G 是连通的并且有 n-1 条边。”
  • @kevmo314 再次正确,但是,森林(树木的集合)也是一个图。因此,如果要严格一点,就不能避免检查周期和连通性。

标签: algorithm graph depth-first-search


【解决方案1】:

正如 kevmo314 在他的评论中提到的,我们需要检查图的连通性和边的数量是否恰好是 n-1,以确保图是一棵树。

所以有两个观察结果:

  • 如果边数为n - 1,我们只需要检查连通性。

  • 对于这个问题,使用disjoint set,作为每条边,如果它是一棵树,这条边应该连接两个断开的组件,否则,这个图不是一棵树。所以时间复杂度是 O(n),因为只有 n - 1 边要检查。

【讨论】:

  • -1 在我在上面的第一条评论中描述的情况下,该算法将失败。您无法在 O(n) 中检查连接性。
  • @alfasin 正如我所说,如果有 n - 1 条边,我们只需要检查连通性,所以 O(n) 会成功。
  • @alfasin 为什么?深度优先搜索的时间复杂度是O(V + E),在这种情况下V = (E + 1) = n,那么时间复杂度是O(2*n) = O(n)?对于带有路径压缩的联合查找,它是 ~ O(n)。
  • @alfasin 这个算法不会失败。这是正确的。发帖人的回答是完全相关的。您在上面描述的情况(一些带有循环的不相交图)将无法通过连通性测试,因为有 n - 1 条边。如果有超过 n - 1 条边,则甚至不需要连通性测试。​​
  • 这是我的最后评论,现在答案已(正确)被 OP 接受。我承认通过将您的一些 cmets 标记为过时且不具建设性而失去了几个声誉点,我没有任何问题。您有足够的声望点来查看足够多的不良 cmets 和答案,以便您很好地了解何时停止以及何时继续。似乎在这个特定的问题中,你的自我阻碍了。我希望你剩下的日子会更好。我是认真的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 2010-11-27
相关资源
最近更新 更多