当前位置:   article > 正文

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

7-1 六度空间

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

法二答案

#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;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/677395
推荐阅读
相关标签
  

闽ICP备14008679号