sicily 1034. Forest

/*

题意:有n个结点,有m条边A->B,判断是不是森林,
如果一结点有两个结点以上同时指向它,即它的入度>1, 或者有环 , 即没有根节点,则不是森林,
若是森林的话,则输出它的深度和宽度, 宽度是指结点数最多的那一层

*/


#include<iostream> // 求森林深度和宽度
#include<stdio.h>

#include<cstring>
#include <algorithm>
using namespace std;
#define maxn 120
int g[maxn][maxn];
int in[maxn],height[maxn]; // in[i]表示结点i的入度数, height[i]表示结点i的高度
int width[maxn]; // width[i]表示在高度i上的结点数

int main()
{
int n,m,i;
while(scanf("%d%d",&n,&m)&&n)
{
int suc=1;
memset(g,0,sizeof(g));
memset(in,0,sizeof(in));
int a,b;
while(m--)
{
scanf("%d%d",&a,&b); //结点下标从 1开始
g[a][b]=1;

if(in[b]==0)
in[b]=1;
else //说明有两条边指向同个结点
suc=0;

}
if(!suc)
{
printf("INVALID\n");
continue;
}
memset(width,0,sizeof(width));

int q[maxn]; //队列存储入度为0的节点

int front=0,rear=0;
for(i=1;i<=n;i++)
{
if(in[i]==0)
{
q[rear++]=i; //把根节点压入栈
height[i]=0;

width[0]++; //一开始所有的根结点都在第0层,高度为 0
}

}
if(rear==0) //找不到根结点,说明有环
{

printf("INVALID\n");
continue;
}
int num=0; // num记录遍历过的结点数
while(front<rear)

{
num++;
int t=q[front++]; //结点t
for(i=1;i<=n;++i)

{
if(g[t][i])
{
height[i]=height[t]+1; //儿子节点的高度比父节点的高度大 1
width[height[i]]++; //在这一高度上的结点数加 1
q[rear++]=i;

}
}
}
if(num<n) //环内任意结点的入度都至少为1,都不会被压入队列,所以小于n说明存在环
{

printf("INVALID\n");
continue;
}
printf("%d %d\n",*max_element(height+1,height+n+1),*max_element(width,width+n));
// 输出森林的高度和宽度,注意 height[i] 表示结点i的高度,而 width[i] 表示在高度i上的宽度
// 高度的范围是从0到n-1,因为根结点是在第0层
}

return 0;
}

posted on 2011-07-04 18:39  sysu_mjc  阅读(356)  评论(0编辑  收藏  举报

导航