特殊路径统计(南航2022数据结构课设第三题)

[问题描述]

给定一颗有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;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值