MOOC PTA 1076 Forwards on Weibo

Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may follow many other users as well. Hence a social network is formed with followers relations. When a user makes a post on Weibo, all his/her followers can view and forward his/her post, which can then be forwarded again by their followers. Now given a social network, you are supposed to calculate the maximum potential amount of forwards for any specific user, assuming that only L levels of indirect followers are counted.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤1000), the number of users; and L (≤6), the number of levels of indirect followers that are counted. Hence it is assumed that all the users are numbered from 1 to N. Then N lines follow, each in the format:

M[i] user_list[i]

where M[i] (≤100) is the total number of people that user[i] follows; and user_list[i] is a list of the M[i] users that followed by user[i]. It is guaranteed that no one can follow oneself. All the numbers are separated by a space.

Then finally a positive K is given, followed by K UserID's for query.

Output Specification:

For each UserID, you are supposed to print in one line the maximum potential amount of forwards this user can trigger, assuming that everyone who can view the initial post will forward it once, and that only L levels of indirect followers are counted.

Sample Input:

7 3
3 2 3 4
0
2 5 6
2 3 1
2 3 4
1 4
1 5
2 2 6

Sample Output:

4
5

 题目大意:假设每个微博用户user[i]的粉丝都会转发他的一次他的分享,求一次分享中最大转发次数。由于粉丝的粉丝也会转发,所以给出了一个限制层数(转手次数)。

         输入的测试数据是:

第一行:用户人数N  限制层数L

接着N行,从1到N分别是每个人关注的人数和 具体关注了谁

        比如 3 2 3 4 就是指用户1 关注了3人 分别是用户2 用户3 用户4

 最后一行是测试的人数K 和具体测试人

        2 2 6 测试2个人,分别是用户2 和用户6 

 整体思路和小结:

        这是一道关于图的问题,重点考察BFS,是“六度空间”理论的改动版,区别是图的边是有向边,且边的总数不是直接给出,而是根据各个顶点的关系得出;所以图结构中将边的域改成限制层数的域;其他基本是一样的;图的遍历是基础知识,需要牢固掌握,诸君共勉;

Six Degrees of Separation  的传送门MOOC 06-图3 六度空间_鸿雁丨红豆灬的博客-CSDN博客

 

 完整代码(个人习惯指针还是带*,容易区别,所以没有将结构指针定位为各种概念,而是直接将结构定义为相应的概念,后续的操作还是和老师的一样的)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int Vertex; //顶点

typedef struct _Egde{ //V1到V2的有向边
	Vertex V1,V2;
}Edge;

typedef struct _AdjV AdjV; //邻接点
struct _AdjV{
	Vertex V;
	AdjV* Next;
};

typedef struct _LGraph{ //邻接表表示的图
	int Nv;
	int Level; //题目中限制BFS的层数
	AdjV** G;  //邻接表G————指针数组,大小根据Nv的值来malloc,数组的每个元素是指向邻接点的指针AdjV*
}LGraph;

typedef struct _Queue{ //队列
	Vertex* Array;
	int front;
	int rear;
}Queue;

LGraph* BuildGraph( );

LGraph* CreateGraph( int N );

void ScanEdge( LGraph* Graph,Vertex V );

void InsertEdge( LGraph* Graph,Edge E );

void ForWardsOnWeibo( LGraph* Graph );

int BFS( LGraph* Graph,Vertex V );

void InitilizeVisited( bool Visited[],int Nv );

Queue* CreateQ( int Nv );

void AddQ( Queue* Q,Vertex V );

Vertex DeleteQ( Queue* Q );

bool IsEmpty( Queue* Q );

void FreeGraph( LGraph* Graph );

int main()
{
	LGraph* Graph = BuildGraph( );

/*	测试建图是否有误
	Vertex V;
	AdjV* p;
	for(V=1;V<Graph->Nv;V++){
		
		printf("%d ",V);
		
		for(p=Graph->G[V];p;p=p->Next){
			
			printf("%d ",p->V);
		}
		
		printf("\n");
	}
*/
	
	ForWardsOnWeibo( Graph );
	
	FreeGraph( Graph );
	
	return 0;
}

//完成图的建立
LGraph* BuildGraph( )
{
	int N;
	scanf("%d",&N);
	LGraph* Graph = CreateGraph( N );
	
	scanf("%d",&Graph->Level);

	Vertex V;
	for(V=1;V<Graph->Nv;V++){
		
		ScanEdge( Graph,V );
	}
	
	return Graph;
}

//建一个初始化的图(只有顶点,没有边)
LGraph* CreateGraph( int N )
{
	LGraph* Graph = (LGraph*)malloc(sizeof(LGraph));
	Graph->Nv = N+1;  //由于顶点编号从1开始,所以+1,G[0]浪费不用
	
    /* 根据顶点个数Nv来确定邻接表的大小*/
	Graph->G = malloc((Graph->Nv)*sizeof(AdjV*));
	
	/* 初始化邻接表 */
	Vertex V;
	for(V=0;V<Graph->Nv;V++){
		
		Graph->G[V] = NULL;
	}
	
	return Graph;
}

//读入关于边的数据
void ScanEdge( LGraph* Graph,Vertex V )
{
	int M,i;
	scanf("%d",&M);
	
	Edge E;
	E.V2 = V;
	for(i=0;i<M;i++){
		
		scanf("%d",&(E.V1));
		
		InsertEdge( Graph,E );
	}
}

//将边插入图中
void InsertEdge( LGraph* Graph,Edge E )
{
	AdjV* NewNode = (AdjV*)malloc(sizeof(AdjV));
	
	NewNode->V = E.V2;
	NewNode->Next = Graph->G[E.V1];
	Graph->G[E.V1] = NewNode;
}

//具体的解题函数
void ForWardsOnWeibo( LGraph* Graph )
{
	int K,MaximunAmountOfForwards;
	scanf("%d",&K);
	
	Vertex V;
	while( K--){
		
		scanf("%d",&V);
		
		MaximunAmountOfForwards = BFS( Graph,V );
		
		printf("%d\n",MaximunAmountOfForwards);
	}
}

//核心的BFS 并返回需要的值
int BFS( LGraph* Graph,Vertex V )
{
	int Level,                   //遍历的层数
		MaximunAmountOfForwards; //题目要求解的返回值
	Level = MaximunAmountOfForwards = 0;
	
	bool Visited[Graph->Nv];     //BFS过程中需要用到的访问标记
	InitilizeVisited( Visited,Graph->Nv ); //每次都需要初始化
	
	Visited[V] = true;
	
	Queue* Q = CreateQ( Graph->Nv); //BFS用到的队列
	
	AddQ( Q,V );
	
	Vertex W,Tail,Last = V;  //Last和Tail 是关于计算遍历层数的关键小套路
	AdjV* p;
	while(!IsEmpty( Q )){
		
		W = DeleteQ( Q );
		
		for(p=Graph->G[W];p;p=p->Next){
			
			if(!Visited[p->V]){
				
				Visited[p->V] = true;
				MaximunAmountOfForwards++;
				
				AddQ( Q,p->V );
				
				Tail = p->V;  
			}
		}
		
		if(W == Last){  //当出队列的是每层的最后一个时
			Level++;
			Last = Tail;//Last等于下一层的最后一个
		}
		
		if(Level == Graph->Level){ //达到题目给出的限制层数,跳出循环
			break;
		}
	}
	
    free(Q->Array);
	free(Q);
	
	return MaximunAmountOfForwards;
}

void InitilizeVisited( bool Visited[],int Nv )
{
	Vertex V;
	for(V=0;V<Nv;V++){
		
		Visited[V] = false;
	}
}

/* 队列的相关操作*/
Queue* CreateQ( int Nv )
{
	Queue* Q = (Queue*)malloc(sizeof(Queue));
	
	Q->Array = malloc(Nv*sizeof(Vertex));
	
	Q->front = Q->rear = -1;
	
	return Q;
}

void AddQ( Queue* Q,Vertex V )
{
	Q->rear++;
	
	Q->Array[Q->rear] = V;
}

Vertex DeleteQ( Queue* Q )
{
	Q->front++;
	
	return Q->Array[Q->front];
	
 } 
 
bool IsEmpty( Queue* Q )
{
	return Q->front == Q->rear ? true : false;
}

//有malloc 就有free
void FreeGraph( LGraph* Graph )
{
	Vertex V;
	AdjV *p,*q;
	for(V=0;V<Graph->Nv;V++){
		
		for(p=Graph->G[V];p;p=q){
			
			q=p->Next;
			free(p);
		}
	}
	
	free(Graph->G);
	free(Graph);
}

                                         

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值