题意理解
著名的六度空间理论,实质上就是图遍历算法的变形,旨在能够更加灵活的使用图遍历算法来解决问题。比如在这道题中,就需要限制遍历的层数或者是说遍历的深度。
六度空间理论的思想就是说,从一个人的关系网出发,任意两个人存在某种关系所需要的中间这不超过六个人。将这里的每个人都看做是图中的顶点,当两个人认识时,这两个顶点就存在一条无向边。
该题就是在给出一张图来验证从图中的任意一个顶点出发在遍历深度不超过六的情况下是否能够完全遍历完这张图。
难点
- 选择合适的图遍历算法
其实这个并不难选择,因为我现在知道的两种图遍历算法就是BFS / DFS ,DFS深度优先,并不是以尽可能多的遍历同层次的顶点为目的,因此,这种算法可先暂且放弃。(但是网上也有大神利用DFS算法将这道题给解出来了,有兴趣的同学可以上网看看) - 控制遍历的层数深度
这个在浙大的数据课上姥姥是给出了一种思路的,但是我在解这道题的时候没看她的思路。我的最开始的思路是记录每层遍历的总结点数,然后当遍历完了这层的节点后就说明进入了下一层中这样就能达到记录遍历深度的目的。
遇到的坑
- C++自带的STL queue容器的效率在题中的最后的一个测试点过不去,最开始我还以为是我计算层数的方法太耗费时间了,在网上搜索了半天,换了姥姥说的那种方法发现还是出现超时的情况,才觉得可能是自带的queue出了问题,后来使用数组进行模拟,最后通过。
需要注意的知识点
使用memset( ) 函数对数组清零,效率要高一些,这个函数包含在 string 头文件中
代码1——自己的思路
#include<stdio.h>
//#include<queue>
#include<cstring>
#define max_size 1000+10
using namespace std;
int visited[max_size];
int graph[max_size][max_size];
//int countAll[max_size];//记录距离不超过6的总节点数 ,啰嗦了
int n, m;
int main()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++)
{
int v1, v2;
scanf("%d %d", &v1, &v2);
graph[v1][v2] = 1;
graph[v2][v1] = 1;
}
for(int i = 1; i <= n; i++)
{
//queue<int> que;
//que.push(i);
int dept = 0; //记录当前遍历的深度
int count = 1; //记录总的节点个数
int cur_level = 1; // 记录当前层一共有多少节点需要遍历
int next_level = 0; // 记录下一层有多少节点
int q[max_size]; // 模拟队列
int start, end; //标记队首,队尾
start = end = 0;
/*for(int j = 1; j <= n; j++)
visited[j] = 0;*/
memset(visited, 0, sizeof(int)*n+10);
memset(q, 0, sizeof(int)*max_size);
q[end++] = i;
while( ( start < end ) && dept <= 6)
{
//int v = que.front();
//que.pop();
int v = q[start++];
visited[v] = 1;
for (int j = 1; j <= n; j++)
{
if(graph[v][j] && dept < 6 && !visited[j])
{
//que.push(j);
next_level++;
count++;
visited[j] = 1;
q[end++] = j;
}
}
//判断层数的方法问题?
if( (--cur_level) == 0) //下一层的节点已经遍历完成
{
dept++;
cur_level = next_level;
//countAll[i] += next_level;
next_level = 0;
}
}
// countAll[i] = count;
printf("%d: %.2f%%\n", i, ((float)count / n) * 100);
}
return 0;
}
代码2——姥姥的思路,也看了看网上的解答
#include<stdio.h>
#include<queue>
#include<string.h>
#define max_size 1000+10
using namespace std;
int visited[max_size];
int graph[max_size][max_size];
int n, m;
void bfs(int p);
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++)
{
int v1, v2;
scanf("%d %d", &v1, &v2);
graph[v1][v2] = 1;
graph[v2][v1] = 1;
}
for (int i = 1; i <= n; i++)
{
memset(visited, 0, sizeof(int)*(n + 10));
bfs(i);
}
return 0;
}
void bfs(int p)
{
int count = 1; //记录总的节点个数
int cur_level = 0; // 记录当前深度
int last = p;
int start, end, q[max_size]; //用于模拟队列,减少使用STL队列带来的时间消耗
visited[p] = 1;
start = end = 0;
q[end++] = p;
while (start < end)
{
int v = q[start++];
if (cur_level == 6)
break;
for (int j = 1; j <= n; j++)
{
if (graph[v][j] && !visited[j])
{
q[end++] = j; // 先end再 ++
visited[j] = 1;
count++;
}
}
//判断层数的方法问题?
if (q[start - 1] == last) // 当进入第二层时,先start再++
{
cur_level++;
last = q[end - 1]; //返回上一个值
}
}
printf("%d: %.2f%%\n", p, (count * 1.0 / n) * 100);
}