[问题描述]
给定一颗有N个节点(编号为1-N)的树。
两个节点a,b(a<b)之间的简单路径上若所有节点编号i均在a,b之间(a≤i≤b),则该路径可标记为特殊路径。
试统计树上一共有多少条特殊路径。
[输入格式]
+ 第一行包含一个整数N,代表节点数
+ 第二行包含N个整数p1,p2,…,pn,代表每个节点的父节点编号。若pi=0,则该节点为树的根节点
[输出数据]
输出树上一共有多少条特殊路径
[补充说明]
+ 0≤pi≤N
+ 有且仅有一个pi=0
+ 输入的图是一棵树
[样例1]
输入:
7
0 5 5 1 4 1 4
输出:
10
[样例2]
输入:
5
2 3 0 2 2
输出:
7
其中样例1的图形示例:
[代码思路]
这道题的目标还是很明确的,根据条件和输入建立图,再统计图中所有两个端点值在该路径中一个为最大,一个为最小的路径,DFS和BFS都能做,只要把所有的路径走一遍,再进行判断是否符合条件就可以了,在这里我所采用的是BFS。
[代码实现]
1.图的建立
typedef struct node
{
int data;//节点数据
node* c[10];//与该结点项链节点的指针
int cnum;//与该节点相连的节点个数
}node;//图的节点定义
int n;
cin >> n;
node* a = new node[n + 1];
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < 10; j++)
a[i].c[j] = NULL;
a[i].cnum = 0;
a[i].data = i;
}//根据第一行输入的节点个数对各节点进行初始化
for (int i = 1; i <= n; i++)
{
int p;
cin >> p;
if (p != 0)
{
a[i].c[a[i].cnum] = &a[p];
a[p].c[a[p].cnum] = &a[i];
a[p].cnum++;
a[i].cnum++;
}
}//根据第二行的输入对各节点进行串联
2. 路径遍历
void BFS(node *t,int min,int max,bool *flag)
{
flag[min] = 1;//标记为1,记为走过
if (t == NULL)
return;
for (int i = 0; i < t->cnum; i++)//遍历与该节点相连的节点
{
if (t->c[i] != NULL && flag[t->c[i]->data] == 0 && !(min > t->c[i]->data))
{//节点不为空,未走过且不比起点小,则可以纳入路径内
flag[t->c[i]->data] = 1;
if (max < t->c[i]->data)//如若遍历到的节点是目前遍历到的最大值,及说明从起点到该节点的路径满足条件
{
sum++;
max = t->c[i]->data;
}
BFS(t->c[i], min, max, flag);//继续遍历
flag[t->c[i]->data] = 0;//重新置为0,表示未走过
}
}
}
for (int i = 1; i < n; i++)//因为遍历路径的起点都是最小值,故n可以不放在循环内
{
bool flag[100] = { 0 };//标记数组,防止进死循环
BFS(&a[i], a[i].data, a[i].data,flag);
}
3.源代码
#include<iostream>
using namespace std;
typedef struct node
{
int data;//节点数据
node* c[10];//与该结点项链节点的指针
int cnum;//与该节点相连的节点个数
}node;//图的节点定义
int sum = 0;
void BFS(node* t, int min, int max, bool* flag)
{
flag[min] = 1;//标记为1,记为走过
if (t == NULL)
return;
for (int i = 0; i < t->cnum; i++)//遍历与该节点相连的节点
{
if (t->c[i] != NULL && flag[t->c[i]->data] == 0 && !(min > t->c[i]->data))
{//节点不为空,未走过且不比起点小,则可以纳入路径内
flag[t->c[i]->data] = 1;
if (max < t->c[i]->data)//如若遍历到的节点是目前遍历到的最大值,及说明从起点到该节点的路径满足条件
{
sum++;
max = t->c[i]->data;
}
BFS(t->c[i], min, max, flag);//继续遍历
flag[t->c[i]->data] = 0;//重新置为0,表示未走过
}
}
}
int main()
{
int n;
cin >> n;
node* a = new node[n + 1];
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < 10; j++)
a[i].c[j] = NULL;
a[i].cnum = 0;
a[i].data = i;
}//根据第一行输入的节点个数对各节点进行初始化
for (int i = 1; i <= n; i++)
{
int p;
cin >> p;
if (p != 0)
{
a[i].c[a[i].cnum] = &a[p];
a[p].c[a[p].cnum] = &a[i];
a[p].cnum++;
a[i].cnum++;
}
}//根据第二行的输入对各节点进行串联
for (int i = 1; i < n; i++)//因为遍历路径的起点都是最小值,故n可以不放在循环内
{
bool flag[100] = { 0 };//标记数组,防止进死循环
BFS(&a[i], a[i].data, a[i].data, flag);
}
cout << sum;
}