题目来源:https://hihocoder.com/problemset/problem/1069?sid=1352614
结题思路:
这里题目就不给大家粘贴了,需要看原题目请点击网址,直接给给大家讲解思路把。
首先明确一点这是一道LCA类问题,解题步骤如下:
- 解题步骤
1.深度优先探索,得出整个探索过程的路径数组,同时在探索过程中存储下族谱树内每个成员的深度值以及最后一次出现在路径数组中的位置,这都可以完全定义在一个结构体中,这道题我看过其他人的解题过程,使用了太多数组,显得代码非常难以理解,不推荐大家使用。
结构体结构如下:
const int MAX_N = 100010;
struct Node_tree
{
string name; // 族谱树中成员的名称
int floor; // 表示族谱树中,该位成员所处的层数
int la_pos; // 深度优先探索的时候,最后一次出现的位置
vector<struct Node_tree*> children; // 存储直系子类成员
}fam[MAX_N];
string trav_fam[MAX_N]; // 存储族谱树的深度优先探索访问顺序
map<string, int> fam_pos; // 辅助族谱树的创建 name 映射 fam数组中的位置
int travt_size = 0, dp[MAX_N][20]; // dp数组用于对获取得到的trav_fam[i]数组进行算法RMQ-ST操作
深度优先探索代码如下:
void ds_famTree(int pos, int floor)
{
fam[pos].la_pos = travt_size; // 存储深度优先探索过程中最后一次出现的位置,这个值肯定是不断在更新的
trav_fam[travt_size++] = fam[pos].name; // 存储探索过程中所经过的结点成员名称
if (0 == fam[pos].children.size()) // 到达叶子结点,存储层数,返回非叶子结点
{
fam[pos].floor = floor; // 记录层数
return;
}
fam[pos].floor = floor; // 记录层数
for (auto son : fam[pos].children)
{
ds_famTree(fam_pos[son->name], floor + 1);
fam[pos].la_pos = travt_size;
trav_fam[travt_size++] = fam[pos].name;
}
}
经历了深度优先探索之后,得到数组trav_fam[i],使用rmq-st算法将其预处理一下(也就是线段树算法),然后获取每次需要查询的区间,输出查询结果。
void RMQ()
{
int N = travt_size - 1; // 探索过程中的路径个数
for (int i = 1; i <= N; i++) // dp数组中存储当前区间中所在层数最小的结点在fam族谱数组中的位置值
{
dp[i][0] = fam_pos[trav_fam[i]];
}
for (int j = 1; (1<<j) < N; j++)
{
for (int i = 1; i + (1 << j) -1 <= N; i++)
{
int a = dp[i][j - 1], b = dp[i + (1 << (j - 1))][j - 1];
dp[i][j] = fam[a].floor < fam[b].floor ? a : b;
}
}
}
最后便是输出结果:
void query(int le, int ri)
{
int k = 0;
while ((1 << (k+1)) <= (ri - le + 1)) // 获取数组dp[i,j]中的j值
{
k++;
}
int a = dp[le][k], b = dp[ri - (1 << k) + 1][k];
cout << (fam[a].floor < fam[b].floor ? fam[a].name : fam[b].name) << endl;
}
void get_res()
{
string per1, per2;
int M;
cin >> M;
for (int i = 0; i < M; i++)
{
cin >> per1 >> per2;
if (per1 == per2)
{
cout << per1 << endl;
continue;
}
int p1 = min(fam[fam_pos[per1]].la_pos,fam[fam_pos[per2]].la_pos);
int p2 = max(fam[fam_pos[per1]].la_pos, fam[fam_pos[per2]].la_pos);
query(p1, p2);
}
}
最终的完整代码如下:
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using std::string;
using std::vector;
using std::map;
using std::cin;
using std::cout;
using std::endl;
using std::max;
using std::min;
const int MAX_N = 100010;
struct Node_tree
{
string name; // 族谱树中成员的名称
int floor; // 表示族谱树中,该位成员所处的层数
int la_pos; // 深度优先探索的时候,最后一次出现的位置
vector<struct Node_tree*> children; // 存储直系子类成员
}fam[MAX_N];
string trav_fam[MAX_N]; // 存储族谱树的深度优先探索访问顺序
map<string, int> fam_pos; // 辅助族谱树的创建 name 映射 fam数组中的位置
int travt_size = 0, dp[MAX_N][20]; // dp数组用于对获取得到的trav_fam[i]数组进行算法RMQ-ST操作
void init()
{
int N;
string fa, son;
scanf("%d", &N);
int per_size = 1;
for (int i = 0; i < N; i++)
{
cin >> fa >> son;
if (0 == fam_pos[fa])
{
fam_pos[fa] = per_size; // 存储在数组 fam 中的标位置
fam[per_size].name = fa;
per_size++;
}
if (0 == fam_pos[son])
{
fam_pos[son] = per_size;
fam[per_size].name = son;
per_size++;
}
fam[fam_pos[fa]].children.emplace_back(&fam[fam_pos[son]]);
}
}
void ds_famTree(int pos, int floor)
{
fam[pos].la_pos = travt_size; // 存储深度优先探索过程中最后一次出现的位置,这个值肯定是不断在更新的
trav_fam[travt_size++] = fam[pos].name; // 存储探索过程中所经过的结点成员名称
if (0 == fam[pos].children.size()) // 到达叶子结点,存储层数,返回非叶子结点
{
fam[pos].floor = floor; // 记录层数
return;
}
fam[pos].floor = floor; // 记录层数
for (auto son : fam[pos].children)
{
ds_famTree(fam_pos[son->name], floor + 1);
fam[pos].la_pos = travt_size;
trav_fam[travt_size++] = fam[pos].name;
}
}
void RMQ()
{
int N = travt_size - 1;
for (int i = 1; i <= N; i++) // dp数组中存储当前区间中所在层数最小的结点在fam族谱数组中的位置值
{
dp[i][0] = fam_pos[trav_fam[i]];
}
for (int j = 1; (1<<j) < N; j++)
{
for (int i = 1; i + (1 << j) -1 <= N; i++)
{
int a = dp[i][j - 1], b = dp[i + (1 << (j - 1))][j - 1];
dp[i][j] = fam[a].floor < fam[b].floor ? a : b;
}
}
}
void query(int le, int ri)
{
int k = 0;
while ((1 << (k+1)) <= (ri - le + 1)) // 获取数组dp[i,j]中的j值
{
k++;
}
int a = dp[le][k], b = dp[ri - (1 << k) + 1][k];
cout << (fam[a].floor < fam[b].floor ? fam[a].name : fam[b].name) << endl;
}
void get_res()
{
string per1, per2;
int M;
cin >> M;
for (int i = 0; i < M; i++)
{
cin >> per1 >> per2;
if (per1 == per2)
{
cout << per1 << endl;
continue;
}
int p1 = min(fam[fam_pos[per1]].la_pos,fam[fam_pos[per2]].la_pos);
int p2 = max(fam[fam_pos[per1]].la_pos, fam[fam_pos[per2]].la_pos);
query(p1, p2);
}
}
int main(void)
{
// 1.创建族谱树
init();
// 2.深度优先探索族谱树,得出探寻轨迹数组
ds_famTree(1, 1);
// 3.使用RMQ-ST算法将获取的路径字数组进行预处理
RMQ();
// 4.获取询问,输出结果
get_res();
getchar();
getchar();
return 0;
}
在此声明:转载请注明出处!!!
同时,题目来源于hihocoder网站,博主在此声明仅使用本题用于代码交流学习,不将用于任何商业用途。