六度空间

问题描述

给一个图,有N个结点 M条边 然后找出每一个结点从当前结点开始 与该节点距离不超过6的结点数占结点总数N的百分比.

题目链接:

https://pintia.cn/problem-sets/15/problems/715

数据范围:

N: 1 < N < 1e3

M: <= 33 *N

样例:

Input:

1
2
3
4
5
6
7
8
9
10
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

Output:

1
2
3
4
5
6
7
8
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%

知识点

图论遍历搜索/计数问题 可采用DFS/BFS求解。

对于该题,把每一个结点的交际圈看成一层,与该节点相连的所有节点都做计数,并与该节点距离小于6的节点做计数。

BFS/DFS的选择:

每一个节点 计算与其联通的所有节点,BFS较好。

BFS模板+计数

初始的BFS模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int BFS(int x)
{
memset(vis, 0, sizeof(vis));
queue<int>q;
q.push(x);
vis[x] = 1;
while(!q.empty())
{
int x = q.front();
//cout << "#:" << x << " ";
q.pop();
for(int i = 1; i <= N; i++)
{
if(vis[i] == 0 && G[x][i] == 1)
{
vis[i] = 1;
q.push(i);
}
}
}
}
  • 对每一个节点进行BFS
  • BFS中累计访问的节点数目
  • 记录“层”数,只计算六层以内的节点数目(难点:如何记录层数)

BFS的记录层数写法详解

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
72
73
74
75
//解释几个变量的具体含义:
G[maxn][maxn]:存图
vis[maxn]:标记该点是否被探索过
?想一下把vis的memset放到BFS里?还是main里?


//首先计数:BFS返回Count来计数
Count:计数距离小于6的节点
int BFS(int x)
{
memset(vis, 0, sizeof(vis));
queue<int>q;
int Count = 1;
q.push(x);
vis[x] = 1;
while(!q.empty())
{
int x = q.front();
q.pop();
for(int i = 1; i <= N; i++)
{
if(vis[i] == 0 && G[x][i] == 1)
{
Count++;
vis[i] = 1;
q.push(i);
}
}
}
return Count;
}


//再记录层数:
//关键点:如何去记录这一层已经结束并标记该下一层?
//ans:标记层数,从当前层数开始 -> 第六层结束
//last:记录当前层的最后一个节点
//tail:记录下一层的最后一个节点
最初赋值 先令last = v;
即当前last指向该节点,然后遍历节点,压缩进队列过程中,将最后一个赋值给tail
然后如果不为空出队过程中,如果last = 出队的节点,对last 重新赋值(下一层最后一个节点->tail)
int BFS(int x)
{
memset(vis, 0, sizeof(vis));
queue<int>q;
int Count = 1;
int tail;
int last = x;
int ans = 0;
q.push(x);
vis[x] = 1;
while(!q.empty())
{
int x = q.front();
q.pop();
for(int i = 1; i <= N; i++)
{
if(vis[i] == 0 && G[x][i] == 1)
{
Count++;
vis[i] = 1;
q.push(i);
tail = i;
}
}
if(last == x)
{
ans++;
last = tail;
}
if(ans == 6)
break;
}
return Count;
}

题目做法

代码

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
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 10;
int G[maxn][maxn];
int vis[maxn];
int N, E;
int BFS(int x)
{
memset(vis, 0, sizeof(vis));//?玄幻错误 放到这里就对...
queue<int>q;
int Count = 1;//计数,是否到达第六个结点
int tail;
int last = x;//记录每一层的最后一个结点
int ans = 0;
q.push(x);
vis[x] = 1;
while(!q.empty())
{
int x = q.front();
//cout << "#:" << flag << " ";
q.pop();
for(int i = 1; i <= N; i++)
{
if(vis[i] == 0 && G[x][i] == 1)
{
Count++;
vis[i] = 1;
q.push(i);
tail = i;
}
}
if(last == x)
{
ans++;
last = tail;
}
if(ans == 6)
break;
}
return Count;
}
int main(void)
{
cin >> N >> E;
for(int i = 0; i < E; i++)
{
int a, b;
cin >> a >> b;
G[a][b] = G[b][a] = 1;
}

for(int i = 1; i <= N; i++)
{
int sovle = BFS(i);
double output = sovle * 100.0 / N;
printf("%d: %.2lf%%\n", i, output);
}
return 0;
}

总结点

  1. BFS/DFS选取可以看问题是要最近/最多/最远进行选择,一般路径最短问题DFS,路径条数问题BFS.
  2. memset在进行初始化中,要看数据范围,在该题,若对G进行初始化,则会发生内存超限。

参考资料

  1. https://www.cnblogs.com/zengguoqiang/p/8429087.html
  2. https://blog.csdn.net/Dream_Weave/article/details/80870033