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

大致题意

给定一个图网络(N)和一个转发层数限制,最多可以传播几层(L),求一条微博在L内最多可以被多少个用户转发,主体上使用BFS的思路,一层层的拓展直到到达L层

思路一

代码如下:

#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>

using namespace std;

const int maxn=1005;
int N,L;
vector<int> list[maxn];
bool vis[maxn] = {false};
int currentLayer=0;
int times=0;
int lastExtendNum[10];
void BFS(int v){
	queue<int> q;
	q.push(v);
	vis[v]=true;
	lastExtendNum[currentLayer]=1;
	while(!q.empty()&&currentLayer<L){
//		printf("NO %d\n",currentLayer+1);
		for(int m=0;m<lastExtendNum[currentLayer];m++){
			int k = q.front();
			q.pop();
		    
			for(int i=0;i<list[k].size();i++){
		        
				if(vis[list[k][i]]==false){
					times++;		        
//					printf("%d ",list[k][i]); 
					vis[list[k][i]]=true;
					q.push(list[k][i]);
					lastExtendNum[currentLayer+1]+=1;
				}	
			}
		}
	
//		printf("\n");
		currentLayer++;
	}
	
	
}

int main(){
	scanf("%d%d",&N,&L);
	int M;
	for(int i=1;i<=N;i++){
		scanf("%d",&M);
		int node;
		for(int k=0;k<M;k++){
			scanf("%d",&node);
			list[node].push_back(i);
		}
	}
//	    printf("5号节点:\n");
//    	for(int i=0;i<list[5].size();i++){
//		printf("%d ",list[5][i]);
//	}
//	printf("\n");
	int queryNum;
	scanf("%d",&queryNum);
	for(int i=0;i<queryNum;i++){
		int queryId;
		scanf("%d",&queryId);
		currentLayer=0;
		times=0;
		for(int k=1;k<=N;k++){
			vis[k]=false;
		}
		memset(lastExtendNum,0,sizeof(lastExtendNum));
		BFS(queryId);
		printf("%d\n",times);
	}
}

while(!q.empty()&&currentLayer<L){
将层数的判断与队列是否为空写在了一起,每次循环一轮,层数+1;
这导致了内部还需要一次循环来控制每轮取出的个数,否则每轮只会取一个数进行拓展,这样只能通过query=2的查询(因为2中每次只会拓展出一个节点),6通不过,6的第二轮拓展出了3个节点,若不加内部一层循环,只会拓展第二轮的一个节点,为空,直接结束,导致最后未到达 7 号节点,次数-1;但是好处是不需要再维护node结构体;

第二种解法

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int n, l, m, k;
struct node{  //带层数的广度优先
    int id, layer;
};
vector<vector<int>> v;  //大小用resize声明则元素类型需要如此定义

int BFS(node tnode);  //返回最大转发量
int main()
{
    cin >> n >> l;
    v.resize(n+1);
    //生成图的邻接表
    for ( int i=1; i<=n; i++ ){
        cin >> m;
        for ( int j=0; j<m; j++ ){
            int tmp;
            cin >> tmp;
            v[tmp].push_back(i);  //tmp→(关注)→i
        }
    }
    //统计k个用户的粉丝量
    cin >> k;
    int tid;
    for ( int i=0; i<k; i++ ){
        cin >> tid;
        node tnode = {tid, 0};  //从直接粉丝开始算第一层
        //遍历指定顶点所在连通块
        printf("%d\n", BFS(tnode));
    }
    
    return 0;
}
int BFS(node tnode){
    bool inq[1010] = {false};  //入队情况
    queue<node> q;
    q.push(tnode);  //初始元素入队
    inq[tnode.id] = true;  //针对id标记入队情况
    int cnt = 0;  //计算转发量
    while( !q.empty() ){
        node top = q.front();  //取出队首元素
        q.pop();  //队首元素出队
        int topid = top.id;  //队首元素id
        for ( int i=0; i<v[topid].size(); i++ ){
            int nextid = v[topid][i];  //邻接顶点id
            if ( inq[nextid]==false && top.layer<l ){  //有层次限制
                node next = {nextid, top.layer+1};
                q.push(next);  //往邻接顶点遍历,层次+1
                inq[next.id] = true;  //标记
                cnt++;
            }
        }
    }
    return cnt;
}

最外层只需判断队列是否为空即可,内部通过node.layer是否超过L来选择是否可以达到下一个节点。队列内不需要两层循环。

总结

两种方法,两种思路,各有优势。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值