PTA 地下迷宫探索(DFS深搜);六度空间(BFS广搜);社交网络图中结点的“重要性”计算

7-1 地下迷宫探索

假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?

输入格式:
输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N≤1000,表示通道所有交叉点和端点)、边数M(≤3000,表示通道数)和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:
若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。

输入样例1:
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5
输出样例1:
1 2 3 4 5 6 5 4 3 2 1

输入样例2:
6 6 6
1 2
1 3
2 3
5 4
6 5
6 4
输出样例2:
6 4 5 4 6 0

tips:
用递归,再外开一个栈(因为退回的时候要输出),注意:回去的时候,要先从栈顶退出自己,再输出此时的栈顶。(不然就输出了两个自己了(一个入栈时的自己一个出栈时的自己))

我的答案:

#include <iostream>
#include <cstring>
#include <stack>
using namespace std;

const int N = 1002;
int n, m, src;
int g[N][N];
int vis[N];
stack<int> stk;

void dfs(int a)
{
	vis[a] = 1;
	if (a == src)
		cout << a;
	else
		cout << ' ' << a;
	stk.push(a);
	for (int i = 1;i <= n;i++)
	{
		if (!vis[i]  && g[a][i] == 1)
			dfs(i);
	}

	stk.pop();
	if (!stk.empty())
		cout << ' ' << stk.top();
}

int main()
{
	memset(vis, 0, sizeof(vis));
	cin >> n >> m >> src;
	int s, d;
	for (int i = 0;i < m;i++)
	{
		cin >> s >> d;
		g[s][d] = g[d][s] = 1;
	}

	dfs(src);

	bool connected = true;
	for (int i = 1;i <= n;i++)
	{
		if (!vis[i])
			connected = false;
	}
	if (!connected)
		cout <<' '<< 0;
}

7-2 六度空间

“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图1所示。

假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。

输入格式:
输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤10^​3,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。

输出格式:
对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。

输入样例:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
输出样例:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%

最终答案:

#include <iostream>
#include <cstring>
#include <iomanip>
#include <queue>
using namespace std;

const int N = 1002;
int n, m;
int g[N][N];
int vis[N];

int bfs(int a)//从点a开始广搜
{
	memset(vis, 0, sizeof(vis));
	int cnt=1;//六步之内能到的人数(包括自己)
	int layer=0;//步数
	queue<int> qu; //啊啊啊啊这个不能写在函数外面,因为退出循环时栈里可能还有一层
	qu.push(a);
	vis[a] = 1;
	int last = a,tail, tmp; //last:上一层最后一个节点,初始化为开始节点
	                          //tail为当前层最后一个节点,每轮tmp不断更新tail
	while (!qu.empty()&&layer<6)
	{
		tmp = qu.front();
		qu.pop();
		for (int i = 1;i <= n;i++)
		{
			if (!vis[i] && g[tmp][i] == 1)
			{
				vis[i] = 1;
				qu.push(i);
				cnt++;
				tail = i;
			}

		}
		if (tmp == last)//当tmp为上一轮最后即为last时,tail即为当前层最后一个节点,此时更新layer
		{
			layer++;
			last = tail;//这一层已访问完毕,这一层已变为下一层的上一层
		}
	}
	return cnt;
}

int main()
{
	memset(vis, 0, sizeof(vis));
	cin >> n >> m ;
	int s, d;
	for (int i = 0;i < m;i++)
	{
		cin >> s >> d;
		g[s][d] = g[d][s] = 1;
	}
	for (int i = 1;i <= n;i++)
	{
		int cnt = bfs(i);
		cout << i << ": " << fixed << setprecision(2) << cnt * 100.0 / n << '%'<<endl;
	}
}

7-3 社交网络图中结点的“重要性”计算

(一道挺简单的题目)
在这里插入图片描述
在这里插入图片描述
输入样例:
9 14
1 2
1 3
1 4
2 3
3 4
4 5
4 6
5 6
5 7
5 8
6 7
6 8
7 8
7 9
3 3 4 9
输出样例:
Cc(3)=0.47
Cc(4)=0.62
Cc(9)=0.35

Tips:
法一:dijkstra
法二:bfs 。因为无权重的图,可以用bfs求最短路径,层数就是最短步数。在题目7-2基础上,把当前layer+1赋给dis[i]。

法一答案:

#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 1001;//不要被题目中的10000骗了,设为1001就能过,否则会内存超限
int n, m;
int g[N][N];
int vis[N];
int dis[N];

void dijkstra(int src)
{
	memset(dis, INF, sizeof(dis));
	memset(vis, 0, sizeof(vis));

	dis[src] = 0;
	for (int j = 1;j <= n;j++)
	{
		int mindis = INF, minvex;
		for (int i = 1;i <= n;i++)
		{
			if (!vis[i] && dis[i] < mindis)
			{
				mindis = dis[i];
				minvex = i;
			}
		}

		vis[minvex] = 1;
		for (int i = 1;i <= n;i++)
		{
			if (!vis[i] && dis[i] > dis[minvex] + g[minvex][i])
			{
				dis[i] = dis[minvex] + g[minvex][i];
			}
		}
	}
}



int main()
{
	memset(g, INF, sizeof(g));
	cin >> n >> m;
	int s, d;
	for (int i = 1;i <= m;i++)
	{
		cin >> s >> d;
		g[s][d] = g[d][s] = 1;
	}
	int cnt, vex;
	cin >> cnt;
	for (int i = 0;i < cnt;i++)
	{
		cin >> vex;
		dijkstra(vex);
		int sum = 0;
		for (int j = 1;j <= n;j++)
		{
			sum += dis[j];
		}		
		cout << "Cc(" << vex << ")=" << fixed << setprecision(2) << (n - 1) * 1.00 / sum <<endl;
	}
}

法二答案

#include <iostream>
#include <cstring>
#include <iomanip>
#include <queue>
using namespace std;

#define INF 0x3f3f3f3f
const int N = 1001;
int n, m;
int g[N][N];
int vis[N];
int dis[N];

void bfs(int a)//从点a开始广搜
{
	memset(dis, INF, sizeof(dis)); //一开始没写这个,然后非连通图过不了
	memset(vis, 0, sizeof(vis));
	int layer = 0;//步数
	queue<int> qu; //啊啊啊啊这个不能写在函数外面,因为退出循环时栈里可能还有一层
	qu.push(a);
	dis[a] = 0;vis[a] = 1; 
	int last = a, tail, tmp; //last:上一层最后一个节点,初始化为开始节点
							  //tail为当前层最后一个节点,每轮tmp不断更新tail
	while (!qu.empty())
	{
		tmp = qu.front();
		qu.pop();
		for (int i = 1;i <= n;i++)
		{
			if (!vis[i] && g[tmp][i] == 1)
			{
				vis[i] = 1;
				qu.push(i);
				dis[i] = layer + 1;
				tail = i;
			}

		}
		if (tmp == last)//当tmp为上一轮最后即为last时,tail即为当前层最后一个节点,此时更新layer
		{
			layer++;
			last = tail;//这一层已访问完毕,这一层已变为下一层的上一层
		}
	}
}

int main()
{

	cin >> n >> m;
	int s, d;
	for (int i = 1;i <= m;i++)
	{
		cin >> s >> d;
		g[s][d] = g[d][s] = 1;
	}
	int cnt, vex;
	cin >> cnt;
	for (int i = 0;i < cnt;i++)
	{
		cin >> vex;
		bfs(vex);
		int sum = 0;
		for (int j = 1;j <= n;j++)
		{
			sum += dis[j];
		}
		cout << "Cc(" << vex << ")=" << fixed << setprecision(2) << (n - 1) * 1.00 / sum << endl;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值