要明确的是这是一个森林,存在很多棵树,我们需要判断输入是否满足产生多颗树的要求,然后再输出森林的深度和宽度。这题有一些陷阱很容易让人判断出错,即使我AC后在写这个解题报告时,也发现了我的代码存在漏洞,可见出题者也没有考虑到一些特殊情况。
我最终修改后的的方法是:首先把所有的根找出来,然后利用宽度优先检索对每一棵树进行分层遍历,并跟踪记录层数和最大的每层数目,作为森林的深度和宽度。遍历过程中,若发现某一节点试图访问已经被访问过的节点时,表示某棵树存在环或者某两个节点同时指向一个节点的情况,这时要及时标记。遍历完毕后还要判断下是否每个节点都被访问过了,因为这是以森林中所有的根为基点往上遍历的,原则上每个点都会被访问,否则表示存在独立的不成树的节点群,这也不符合森林的特点。我先前的另一个AC代码和这个方法有比较大的不同,但在逻辑判断上就是漏了最后一种情况,即存在独立的不成树的节点群没有却被有效地判断出来。
Run Time: 0sec
Run Memory: 312KB
Code length: 2054Bytes
SubmitTime: 2011-12-24 22:34:02
// Problem#: 1034
// Submission#: 1123477
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int main()
{
int n, m;
int i, j;
int parent;
int depth, width;
bool valid, bottom;
bool visited[ 101 ];
bool edge[ 101 ][ 101 ];
while ( cin >> n >> m && n ) {
memset( visited, false, sizeof( visited ) );
memset( edge, false, sizeof( edge ) );
while ( m-- ) {
cin >> i >> j;
edge[ i ][ j ] = true;
}
queue<int> q;
for ( i = 1; i <= n; i++ ) {
for ( j = 1; j <= n; j++ ) {
if ( edge[ j ][ i ] )
break;
}
if ( j > n ) {
q.push( i );
visited[ i ] = true;
}
}
depth = 0;
width = q.size();
valid = ( q.size() != 0 ? true: false );
while ( valid && !q.empty() ) {
parent = q.size();
if ( parent > width )
width = parent;
bottom = true;
while ( valid && parent-- ) {
i = q.front();
for ( j = 1; valid && j <= n; j++ ) {
if ( edge[ i ][ j ] ) {
bottom = false;
if ( visited[ j ] )
valid = false;
else {
q.push( j );
visited[ j ] = true;
}
}
}
q.pop();
}
if ( bottom == false )
depth++;
}
if ( valid ) {
for ( i = 1; i <= n; i++ ) {
if ( !visited[ i ] ) {
valid = false;
break;
}
}
}
if ( valid )
cout << depth << " " << width << endl;
else
cout << "INVALID" << endl;
}
return 0;
}