Sicily 1034. Forest

本文详细介绍了如何通过宽度优先搜索算法计算森林的深度和宽度,包括算法流程、注意事项及代码实现,特别强调了避免常见陷阱的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要明确的是这是一个森林,存在很多棵树,我们需要判断输入是否满足产生多颗树的要求,然后再输出森林的深度和宽度。这题有一些陷阱很容易让人判断出错,即使我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;

}                                 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值