方法来源:http://blog.csdn.net/guozhengchun/article/details/40761255
判断森林是否合法,以及找出最大宽度跟深度,上面博客的方法很好,是将森林变成树来处理的
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
struct node{
int dad; //父节点
int child_num; //子节点数
int child[101]; //子节点编号
node(){
dad=-1;
child_num=0;
for(int i=0; i < 101; ++i) child[i]=-1;
}
};
int main()
{
int n,m;
while(cin >> n >> m){
node nn[101];
if(n==0) break;
if(m==0){
cout << "0 " << n << endl;
continue;
}//没有边时 深度为0,但宽度为所有节点数
int a,b;
for(int i=0; i < m; ++i){
cin >> a >> b;
nn[a].child[nn[a].child_num++] = b;//记录a的子节点为b
nn[b].dad=a;//b的父节点为a
}
bool check=false;//合法的
int bian=m;//合成树后的新总边数
for(int i=1; i <= n; ++i){
if(nn[i].dad==i){
check=true;
break;
}//节点的父节点为本身,是环不合法,结束
if(nn[i].dad==-1){
nn[i].dad=0;
nn[0].child[nn[0].child_num++]=i;
bian++;
}//没有父节点的节点,作为节点0的子节点,然后新总边数+1
}
if(n!=bian||check==true||m==bian){
cout << "INVALID" << endl;
continue;
}/* n!=bian说明存在入度不为1的节点,因为新树的节点数为n+1
正常的话节点=边数+1,即n+1=bian+1,如果不是就是说明有入度超过1
check==true说明有节点的父节点为本身
m==bian说明所有节点构成一个环
*/
queue<node> q;
q.push(nn[0]);
int maxwidth=-1;//记录最大的宽度,也就是我们要的结果
int pos=0;//当前结点在当前这一层的第几个位置,用于判断当前这层是否遍历完了
int nowwidth=1;//当点所在这层的宽度
int nextwidth=0;//下一层的宽度
int depth=-1;//深度,因为加了一个不存在的头节点,所以要从-1开始
int nodecount=0;//这棵树中总的节点数,用来判断是否存在环没有组成这颗树
node now;
while(!q.empty()){
now=q.front();
q.pop();
nodecount++;
for(int i=0; i < now.child_num; ++i)
q.push(nn[now.child[i]]);//将下一层的节点入队
pos++;
nextwidth+=now.child_num;//计算下一层的节点数,也就是宽度
if(pos==nowwidth){//如果当前位置到了这一层的最后一个节点
if(nextwidth > maxwidth)
maxwidth=nextwidth;//更新最大的宽度
nowwidth=nextwidth;//更新当前的宽度为下一层的宽度
nextwidth=0;//将下一层的宽度初始化为0
depth++;//深度加一
pos=0;// 初始化记录的位置
}
}
if(nodecount-1==n){
cout << depth-1 << " " << maxwidth << endl;
}
else cout << "INVALID" << endl;//存在环没构成树
}
}