sicily1034

这道题也算是一道简单题,但是因为我太水,以至于提交了很多次才AC,先说一下题目的大概意思吧:定义了一个叫森林的有向图,有节点和节点之间的边,只有该有向图是无环和没有2条指向同一节点的边的才能叫做森林,根节点的层数为0,根节点无父节点,输入节点和边的信息,需要输出该森林的最大深度和最大宽度

我的思路是,首先接受输入,同时进行判断是否有2条指向同一节点的边,接着就判断该有向图是否有环(DFS),如果无环则继续为每个节点赋予深度(DFS),其实这两个DFS应该可以结合来简化代码的,但是我太懒了,时间也没那么多,就没简化,最后是遍历整个有向图来找到最大宽度。刚开始为什么WA是因为我忽略了几点:1. 一个节点是可以有多个儿子的;2. 有环的情况可以是自己指向自己,或者自己指向儿子不断下去最终指回自己。AC之后我看了网上大牛牛们的做法,一般都是用DFS,不过他们判断有环的方法跟我的不太一样,感觉他们的代码更加简洁!

还有一个就是做这道题过程中知道原来不能直接对vector用memset(),具体原因是vector是使用名称为“_Myproxy”、“_Mynextiter”这两个指针来寻找与之相邻的值的,在我们定义一个向量时,它便初始化一个“_Myproxy”,当使用了memset的时候,导致了vector中的“_Myproxy”丢失,虽然仍可以对其进行push_back()等其他几乎一切操作,但是这个向量缺唯独不能执行遍历这一种操作!遇到这个错误我也是醉了...不过遇到这种这么隐晦的错误我也挺感恩的,最起码知道了不是所有东西都可以随便套上memset来进行清零操作的!

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

废话不多说,详见代码,代码来不及变美,勿喷~:

#include <iostream>
#include <cstdio>
#include <vector>
#include <memory.h>
#include <algorithm>

using namespace std;

struct node
{
	int num;
	int depth;
	int parent;
	vector<int> sons;
};

//node que[110];
int maxd = 0;
int maxw = 0;

bool findSelf( node q[], int k, int tofind )
{
	if ( q[k].sons.empty() )
	{
		return false;
	}
	else
	{
		vector<int>::iterator it = q[k].sons.begin();
		for ( ; it != q[k].sons.end(); it++ )
		{
			if ( tofind == (*it) )
			{
				return true;
			}
			else
			{
				return findSelf( q, (*it), tofind );
			}
		}
	}
}

bool dfs( node q[], int j )
{
	maxd = max( q[j].depth, maxd );
	if ( q[j].sons.empty() )
	{
		return true;
	}
	else
	{
		vector<int>::iterator it;
		for ( it = q[j].sons.begin(); it != q[j].sons.end(); it++ )
		{
			q[(*it)].depth = q[j].depth + 1;
			dfs( q, (*it) );
		}
		return true;
	}
}

int main()
{
	//freopen( "1034input.txt", "r", stdin );
	//freopen( "1034out.txt", "w", stdout );

	int n;
	while ( cin >> n )
	{
		int m;
		cin >> m;

		if ( n == 0 )
		{
			break;
		}

		maxd = 0;
		maxw = 0;
		node que[110];
		//memset( que, 0, sizeof( que ) );

		int isValid = 1;

		// 初始化数组
		for ( int i = 1; i <= n; i++ )
		{
			que[i].num = i;
			que[i].depth = -1;
			que[i].parent = -1;
		}

		//接受边的输入
		int pp, ss;
		for ( int i = 0; i < m; i++ )
		{
			cin >> pp >> ss;

			//如果该儿子已经有父亲了,则不再赋值,这个也不是森林
			if ( que[ss].parent != -1 )
			{
				isValid = 0;
			}
			else
			{
				que[ss].parent = pp;
			}
			que[pp].sons.push_back( ss );
		}

		//判断有环的情况
		if ( isValid == 1 )
		{
			for ( int k = 1; k <= n; k++ )
			{
				if ( que[k].sons.empty() )
				{
					continue;
				}
				else
				{
					isValid = !( findSelf( que, k, k ) );
					if ( isValid == 0 )
					{
						break;
					}
				}
			}
		}

		if ( isValid == 1 )
		{
			//为每个节点找到其深度,先找root,再排下来
			bool isRoot[110];
			memset( isRoot, true, sizeof( isRoot ) );

			//找root,对每个root,深度记为0;
			for ( int j = 1; j <= n; j++ )
			{
				if ( que[j].parent != -1 )
				{
					isRoot[j] = false;
				}
				else
				{
					que[j].depth = 0;
				}
			}

			//从root开始,为每个节点赋予深度
			for ( int j = 1; j <= n; j++ )
			{
				int dd = 0;
				if ( isRoot[j] == true )
				{
					dfs( que, j );
				}
			}

			//找到每个深度所对应的广度
			int width[110];
			memset( width, 0, sizeof( width ) );
			for ( int j = 1; j <= n; j++ )
			{
				width[que[j].depth]++;
			}

			for ( int j = 0; j < n; j++ )
			{
				if ( width[j] > maxw )
				{
					maxw = width[j];
				}
			}

			cout << maxd << " " << maxw << endl;
		}
		else
		{
			cout << "INVALID" << endl;
		}

	}

	return 0;
}

这道题在看算法课的ppt的时候,给的提示是使用队列和搜索,但是使用队列的话就得是BFS了,感觉会更麻烦呢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值