这道题也算是一道简单题,但是因为我太水,以至于提交了很多次才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了,感觉会更麻烦呢!