算法设计与分析实验三:d森林问题

d森林问题

1. 问题描述
设T为一带权树,树中的每个边的权都为整数。又设S为T的一个顶点的子集,从T中删除S中的所有结点,则得到一个森林,记为T/S。如果T/S中所有树从根到叶子节点的路径长度都不超过d,则称T/S是一个d森林。设计一个算法求T的最小顶点集合S,使T/S为一个d森林。
2. 题目分析
本问题可用贪心算法解。从每个叶子节点向根节点移动,若路途中路长超过d则将子树分离。(1)贪心选择性质:若某一最优解某一步不符合贪心选择,则该步骤得到的子树长度要么和贪心选择得到的相同,要么比贪心选择得到的要短。若相同则贪心选择也可以得到最优解;否则原解不是最优解。(2)最优子结构性质:原树的某一子树删去S中结点(若有)显然也满足森林从根到叶子节点的路径长度都不超过d。
3. 程序设计
数组leaf存储叶节点;数组isCut存储某一结点是否被删去;数组parent存储双亲结点;数组parlen存储某节点到双亲结点的权值;数组dis存储某结点到叶节点的距离.函数cutAndDelete用于问题求解.若当前节点不是根节点,则向上移动,路长超过d且未分离时将结点删除并向根节点移动;若没有超过d则更新dist数组.若出度为0则将该结点添加到叶子节点数组leaf.主函数中先输入并建立树,再调用cutAndDelete求解.
4. 代码

#include "iostream"
#include "fstream"
#include "queue"
using namespace std;
const int maximum = 10000;
int leaf[maximum];
int isCut[maximum];
int parent[maximum];
int parlen[maximum];
int dis[maximum];
int outdeg[maximum];
int cutAndDelete(int n, int d)
{
	int i = 0; int num = 0;
	for (i = 1; i <= leaf[0]; i++)
	{
		if (leaf[i] != 1)
		{
			int p = parent[leaf[i]];
			int len = parlen[leaf[i]];
			if (isCut[p] == 0 && dis[leaf[i]] + len > d)
			{
				num++;
				isCut[p] = 1;
				p = parent[p];

			}
			else if (isCut[p] == 0 && dis[p] < len + dis[leaf[i]])
			{
				dis[p] = len + dis[leaf[i]];
			}
			if (--outdeg[p] == 0)
			{
				leaf[++leaf[0]] = p;
			}
		}

	}
	return num;
}
int main()
{
	ifstream input("exp3_in.txt");
	int nodenum, a, i, j, k, n, d, t;
	input >> nodenum;
	for (i = 0; i < nodenum; i++)
	{
		memset(leaf, 0, sizeof(leaf));
		memset(parlen, 0, sizeof(parlen));
		memset(isCut, 0, sizeof(isCut));
		memset(dis, 0, sizeof(dis));
		memset(outdeg, 0, sizeof(outdeg));
		memset(parent, 0, sizeof(parent));
		input >> n >> d;
		for (j = 1; j <= n; j++)
		{
			input >> outdeg[j];
			if (outdeg[j] != 0)
			{
				for (k = 0; k < outdeg[j]; k++)
				{
					input >> t;
					t += 1;
					input >> a;
					parent[t] = j;
					parlen[t] = a;
				}
			}
			else if (outdeg[j] == 0)
			{
				leaf[++leaf[0]] = j;
			}
		}
		int result;
		result = cutAndDelete(n, d);
		cout << result << endl;
	}
	return 0;
}

5. 运行结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值