ZOJ2682 People like People,深度优先搜索

这题有点难度,不过理清题目后还是可以解决的。首先我们把全部节点都视为core节点。把出度为0的节点剔除掉,同时也可以把指向出度为0的节点的节点也剔除掉。把入度为0的节点剔除,同时修改它指向的节点的入度。不断重复直到没有可以剔除的节点了。这样余下的节点都可以构成core。这里可以构成一个或多个core,我们必须找到core成员数最多的,这时可以用深度遍历了。


/*******************************************************************************
 # Author : Neo Fung
 # Email : neosfung@gmail.com
 # Last modified: 2011-09-23 20:28
 # Filename: ZOJ2682 People like People.cpp
 # Description : 先剔除掉所有不符合题目要求的节点,接着深度检索余下的节点
 ******************************************************************************/
// ZOJ2682 People like People.cpp : Defines the entry point for the console application.
//

// #include "stdafx.h"
// #define DEBUG

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <memory.h>

#define MAX 10010

using namespace std;

struct NODE
{
	int to;
	NODE *next;
}*v[MAX],*rv[MAX],node[6*MAX];//v记录的是正序,rv记录的是转置后的
int n,m,ncount;
int in[MAX],out[MAX],visit[MAX];

void init(void)
{
	memset(v,'\0',sizeof(v));
	memset(rv,'\0',sizeof(rv));
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	memset(visit,0,sizeof(visit));//visit用于记录那些被剔除掉的节点
	ncount=0;
}
void dele(void)
{
	bool flag=true;
	while(flag)
	{
		flag=false;
		for(int i=1;i<=n;++i)
			if(!visit[i])
			{
				if(in[i]==0)	//对于所有入度为0的节点,把他们剔除掉
				{
					NODE *head=v[i];
					while(head)
					{
						--in[head->to];//把边也剔除掉
						head=head->next;
					}
					visit[i]=1;
					flag=true;
				}
				if(out[i]==0)	//找到所有出度为0的节点,也剔除掉
				{
					NODE *head=rv[i];
					while(head)
					{
						out[head->to]=0;	//如果节点的出度为0,则指向它的节点因为指向了core外的节点,故也必须剔除,这里把这些节点的出度设为0留到下一次剔除
						head=head->next;
					}
					visit[i]=1;
					flag=true;
				}
			}
	}
}

int dfs(int index,int sum)
//深度检索,对于一个节点,只要没有被访问过,就深度检索它指向的,以及指向它的节点
{
	if(visit[index]) return sum;
	++sum;
	visit[index]=1;
	NODE *head=v[index];
	while(head)
	{
		sum=dfs(head->to,sum);
		head=head->next;
	}
	head=rv[index];
	while(head)
	{
		sum=dfs(head->to,sum);
		head=head->next;
	}
	return sum;
}
int main(void)
{
#ifdef DEBUG  
	freopen("data.txt","r",stdin);  
#endif  
	int ncases,start,end,temp;
	scanf("%d",&ncases);
	while(ncases--)
	{
		scanf("%d %d",&n,&m);
		init();
		for(int i=0;i<m;++i)
		{
			scanf("%d %d",&start,&temp);
			for(int j=0;j<temp;++j)
			{
				scanf("%d",&end);
				node[ncount].to=end;
				node[ncount].next=v[start];
				v[start]=&node[ncount++];
				node[ncount].to=start;
				node[ncount].next=rv[end];
				rv[end]=&node[ncount++];
				++in[end];
				++out[start];
			}
		}
		dele();
		int maxsum=0,temp;
		for(int i=1;i<=n;++i)
		{
			temp=dfs(i,0);
			if(temp>maxsum)
				maxsum=temp;
		}
		printf("%d\n",maxsum);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值