XMU 算法分析与设计第三次上机题解

文章介绍了使用BFS解决微博转发的最大可能转发量问题,利用DFS计算不同路径数,应用并查集处理合并集合操作,堆排序求解前k小的数,以及分组背包和最短路Floyd算法解决消防安全指挥问题和铺设光纤问题,最后讨论了多重背包问题及其求解策略。


在这里插入图片描述

一、BFS试炼之微博转发

BFS试炼之微博转发

描述

微博上的用户既可能有很多关注者,也可能关注很多其他用户。

因此,形成了一种基于这些关注关系的社交网络。

当用户在微博上发布帖子时,他/她的所有关注者都可以查看并转发他/她的帖子,然后这些人的关注者可以对内容再次转发…

现在给定一个社交网络,假设只考虑L层关注者,请你计算某些用户的帖子的最大可能转发量。

补充

如果B是A的关注者,C是B的关注者,那么AA的第一层关注者是B,第二层关注者是C。

输入

第一行包含两个整数,N表示用户数量,LL示需要考虑的关注者的层数。

假设,所有的用户的编号为1∼N。

接下来N行,每行包含一个用户的关注信息,格式如下:

M[i] user_list[i]

M[i]是第ii名用户关注的总人数,user_list[i]是第ii名用户关注的M[i]个用户的编号列表。

最后一行首先包含一个整数K,表示询问次数,然后包含K个用户编号,表示询问这些人的帖子的最大可能转发量。

数据范围

1≤N≤1000,
1≤L≤6,
1≤M[i]≤100,
1≤K≤N

输出

按顺序,每行输出一个被询问人的帖子最大可能转发量。

假设每名用户初次看到帖子时,都会转发帖子,只考虑L层关注者。

输入样例 1

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

输出样例 1

4
5

解题思路:

  • 可以转变为,求解一张有向图中,到指定点的距离 ≤ \leq L的点的个数。即用BFS来遍历图
  • 若A关注了B,则B的帖子可以抵达A,A可以转发B的帖子。创建<B,A>边
  • 用链式前向星创建图

代码实现:

#include<iostream>
#include<queue>
#include<string.h>
#define MaxSize 1050
using namespace std;
int N, L, K;

//无权值的链式前向星
typedef struct Edge {
   
   
	int to,next;
} Edge;
int tot;
int head[MaxSize];//head[i],第i个点的第一个孩子结点的索引
Edge edge[MaxSize];

//加边函数
void add_edge(int u, int v) {
   
    //u为起点,v为终点,w为权值
	edge[tot].to = v; //tot为空结点指针
	edge[tot].next = head[u];
	head[u] = tot++;//tot为任一个未被使用的空节点指针。
}
int BFS(int num) {
   
   
	int sum = 0;
	int flag[MaxSize] = {
   
   0};//标记已满足要求的点
	flag[num]=1;
	queue<int> q;
	for (int i = head[num]; i != -1; i = edge[i].next) {
   
   
		q.push(edge[i].to);
		flag[edge[i].to] = 1;
		sum++;
	}

	for (int i = 2; i <= L; i++) {
   
   
		int Q_size = q.size();//存每一层的大小
		while (Q_size--) {
   
   
			int t = q.front();//取栈顶
			q.pop();
			for (int j = head[t]; j != -1; j = edge[j].next) {
   
   
				if (flag[edge[j].to] != 1) {
   
   //若未取过
					q.push(edge[j].to);
					flag[edge[j].to] = 1;
					sum++;
				}
			}
		}
	}
	return sum;
}
int main() {
   
   
	cin >> N >> L;
	memset(head, -1, sizeof head);
	//输入数据
	int x, y;
	for (int i = 1; i <= N; i++) {
   
   
		cin >> x;
		for (int j = 0; j < x; j++) {
   
   
			cin >> y;
			add_edge(y, i);
		}
	}
    //查看图的建立是否正确
//	for (int i = 1; i <= MaxSize; i++) { //从1开始
//		for (int j = head[i]; j != -1; j = edge[j].next) {
   
   
//			printf("结点%d->结点%d\n", i, edge[j].to);
//		}
//	}
	//咨询K个人的转发量
	cin >> K;
	int num;
	while (K--) {
   
   
		cin >> num;
		cout << BFS(num)<<endl;
	}
}

二、DFS试炼之不同路径数

DFS试炼之不同路径数

描述

给定一个n×m的二维矩阵,其中的每个元素都是一个[1,9]之间的正整数。

从矩阵中的任意位置出发,每次可以沿上下左右四个方向前进一步,走过的位置可以重复走。

走了k次后,经过的元素会构成一个(k+1)位数。

请求出一共可以走出多少个不同的(k+1)位数。

输入

第一行包含三个整数n,m,k。

接下来n行,每行包含m个空格隔开的整数,表示给定矩阵。

数据范围

1≤n,m≤5,

0≤k≤5,

m×n>1

输出

输出一个整数,表示可以走出的不同(k+1)位数的个数。

输入样例 1

3 3 2
1 1 1
1 1 1
2 1 1

输出样例 1

5

解题思路:

  • 根据题意,可以用DFS遍历得到,从[x,y]出发走k步的每一种情况
  • 将每种情况存入set集合即可自动去重
  • 注意:每一步不能同时走x,y

代码实现:

#include<iostream>
#include<set>
using namespace std;
set<int> s;
int n, m, k;
int Arr[10][10];

int dx[4] = {
   
   -1, 0, 1, 0}, dy[4] = {
   
   0, 1, 0,-1};//一次走一步,走x不走y
void dfs(int x, int y, int q, int value) {
   
    //第q步的横坐标x,纵坐标y,当前值value
	if (q == k) {
   
   //若为第k步,将当前值加入set
		s.insert(value);
		return ;
	}
	for (int i = 0; i < 4; i++) {
   
   
		int xx = x + dx[i];
		int yy = y + dy[i];
		if (xx < n && yy < m && xx >= 0 && yy >= 0)
			dfs(xx, yy, q + 1, value * 10 + Arr[xx][yy]);
	}
}
int main() {
   
   
	cin 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快苏排序OAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值