Sicily 1034 Forest

题目:http://soj.me/1034

题目大意:

给出一个森林,首先判断这个森林是否合法,然后求出这个森林的最大深度和最大宽度。

不合法的意思是:有环或者存在多个结点指向同一个结点的情况。

最大深度的定义是:所有树的深度的最大值,根结点的深度为0。

最大宽度的定义是:同一层的结点总数为该层的宽度,所有层的最大宽度为森林的最大宽度。

算法实现:

       用拓扑排序的方法判断有向图是否有环,然后用dfs求出最大深度和最大宽度,同时判断是否有多个结点指向同一个结点的情况(被指向的结点会被访问多次)。

具体代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#define MAXN 101
using namespace std;

struct ArcNode
{
    int adjvex;
    ArcNode *next;
};
struct VNode
{
    ArcNode *first;
};
struct Graph
{
    int vexnum;
    VNode v[MAXN];
};

int max_depth;
int in[MAXN],vis[MAXN],node_num[MAXN];
Graph g;

bool dfs(int cur,int level)
{
    if(vis[cur]) return 0;
    vis[cur]=1;
    node_num[level]++;
    if(g.v[cur].first==NULL)
    {
        if(level>max_depth)
            max_depth=level;
        return 1;
    }
    ArcNode *p;
    for(p=g.v[cur].first;p;p=p->next)
        if(!dfs(p->adjvex,level+1))
            return 0;
    return 1;
}
/**利用拓扑排序判断有向图是否有环*/
bool topological_sort(Graph &g,int *in)
{
    int *indegree=(int *)malloc((g.vexnum+1)*sizeof(int));
    memcpy(indegree,in,(g.vexnum+1)*sizeof(int));
    stack<int> s;
    for(int i=1;i<=g.vexnum;i++)
        if(indegree[i]==0)
            s.push(i);
    int cnt=0;
    while(!s.empty())
    {
        int i=s.top();
        s.pop();
        cnt++;
        ArcNode *p;
        for(p=g.v[i].first;p;p=p->next)
        {
            int k=p->adjvex;
            indegree[k]--;
            if(indegree[k]==0)
            {
                s.push(k);
            }
        }
    }
    free(indegree);
    if(cnt<g.vexnum) return 0;
    return 1;
}
int main()
{
    int n,m;
    while(cin>>n>>m&&n>0)
    {
        g.vexnum=n;
        for(int i=1;i<=n;i++)
            g.v[i].first=NULL;
        memset(in,0,sizeof(in));
        for(int i=1;i<=m;i++)
        {
            int v1,v2;
            cin>>v1>>v2;
            in[v2]++;
            ArcNode *tmp=new ArcNode();
            tmp->adjvex=v2;
            tmp->next=g.v[v1].first;
            g.v[v1].first=tmp;
        }
        if(!topological_sort(g,in))
        {
            cout<<"INVALID"<<endl;
            continue;
        }
        bool invalid=0;
        memset(vis,0,sizeof(vis));
        max_depth=0;
        memset(node_num,0,sizeof(node_num));
        for(int i=1;i<=n;i++)
            if(in[i]==0)
            {
                if(!dfs(i,0))
                {
                    invalid=1;
                    break;
                }
            }
        if(invalid)
        {
            cout<<"INVALID"<<endl;
            continue;
        }
        int max_width=0;
        for(int i=0;i<MAXN;i++)
            if(node_num[i]>max_width)
                max_width=node_num[i];
        cout<<max_depth<<" "<<max_width<<endl;
    }
    return 0;
}

收获:用拓扑排序判断有向图是否有环的方法是判断是否所有结点都被排序,如果存在没有被排序的结点,那么就会有环。这个一个比较保险的方法。如果使用对每个结点都进行dfs,根据是否存在被重复访问的结点判断是否有环的方法,是不正确的。因为我们不知道结点的访问顺序,从而会出现孩子结点被重复访问的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值