有向树独立k中值问题

 代码如下:

#include <iostream>
#include <stdio.h>
using namespace std;
int n,k;//n个边,k个独立服务机构 
typedef struct Node 
{
	//w记录总权值包括子结点,d距离服务机构(根节点)的距离,wd记录总运费,parent为父节点,
	//lchild,rchild为孩子结点,wx记录该结点的权值,dx记录该结点的边长 
	int w,d,parent,lchild,rchild,wx,wd,dx;
	int cost[100];							//记录费用 
}BiNode;									//定义一个结构体
BiNode sub[100];
void findc(int b,int i)						//关联结点的函数 
{
	sub[i].parent=b;						//i的父结点为b 
	if(sub[b].lchild==-1) sub[b].lchild=i;	//如果b没有左子树,则令b为他的左子树 
	else sub[b].rchild=i;					//如果b有左子树,则令b为他的右子树 
}
void PreOrder(int t)						//先序遍历,找出总距离 
{
	if(t!=-1)								//若i为存在的结点下标 
	{
		if(sub[t].parent!=-1)				//若i存在父节点 
		{
			sub[t].d+=sub[sub[t].parent].d;//距离加上父节点离服务区的距离 
		}
		PreOrder(sub[t].lchild);			//遍历出叶子结点离服务区的距离 
		PreOrder(sub[t].rchild);			//遍历出叶子结点离服务区的距离 
	}
}
void PostOrder(int t)						//后序遍历找出总运费和总权值 
{
	if(t!=-1)								//若i为存在的结点下标 
	{
		PostOrder(sub[t].lchild);			//先遍历出叶子结点的运费
		PostOrder(sub[t].rchild);			//先遍历出叶子结点的运费
		sub[t].wd=sub[t].w*sub[t].d;		//求总运费 
		if(sub[t].lchild!=-1)				//若i存在左子节点
		{
			sub[t].w+=sub[sub[t].lchild].w;	//加上左结点的权值 
			sub[t].wd+=sub[sub[t].lchild].wd;//加上左结点的运费 
		}
		if(sub[t].rchild!=-1)				//若i存在右子节点
		{
			sub[t].w+=sub[sub[t].rchild].w;//加上右结点的权值 
			sub[t].wd+=sub[sub[t].rchild].wd;//加上右结点的运费
		}
	}
}
void Comp(int t)							//动态规划,找出最小转移费用
{
	if(sub[t].lchild==-1)					//该结点为叶子结点 
	{
		sub[t].cost[0]=sub[t].wd; 			//转移费用
		for(int i=1;i<=k;i++)				//同一个地方建立1-k个服务站 
			sub[t].cost[i]=0;				//设立服务站的地方花费设为0 
	}
	else									//如果不为叶子结点
	{
		for(int i=0;i<=k;i++)				//建立1-k个服务站 
		{
			sub[t].cost[i]=sub[t].wd-sub[t].w*sub[t].d;//记录运费 
			for(int j=0;j<=i;j++)			//设立0-i个服务站 
			{
				int tmp = sub[sub[t].lchild].cost[j]+sub[t].wx*sub[t].d;//距离与权相乘为运费,加上左结点的运费 
				if(sub[t].lchild!=-1) tmp+=sub[sub[t].rchild].cost[i-j];//若有右结点,加上右结点
				if(sub[t].cost[i]>tmp)  sub[t].cost[i]=tmp;				//找到比tmp大的,然后用tmp替换掉 
			}
		}
	}
}
void PostOrderComp(int t)					//后序遍历
{
	if(t!=-1)
	{
		PostOrderComp(sub[t].lchild);		//先找齐叶子节点
		PostOrderComp(sub[t].rchild);		//先找齐叶子节点
		Comp(t);							//动态规划,找出各个结点最小转移费用 
	}
}
int main()
{
	FILE *fp=fopen("输入.txt","r");         //文件输入数据 
	fscanf(fp,"%d %d",&n,&k);				//文件输入边数和独立服务机构个数 
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=n;j++)				//初始化
			sub[i].cost[j]=0;
		sub[i].dx=sub[i].d=sub[i].w=sub[i].wx=sub[i].wd=0;	//初始化
		sub[i].parent=sub[i].lchild=sub[i].rchild=-1;		//全部初始化为-1 
	}
	int a,b,c;
	for(int i=1;i<=n;i++)					//输入数据 
	{
		fscanf(fp,"%d %d %d",&a,&b,&c);		//输入 
		sub[i].wx=sub[i].w=a;				//记录权值 
		sub[i].dx=sub[i].d=c;				//长度 
		findc(b,i);							//关联结点,找到该结点父结点 
	}
	PreOrder(0);							//先序遍历,找出距离根节点距离 
	PostOrder(0);							//后序遍历, 找出总运费和权值 
	PostOrderComp(0); 						//后序遍历设立服务站 
	printf("%d\n",sub[0].cost[k]);			//输出最小转移费用,即根节点的花费cost[k]值 
} 

输入格式

4 2
1 0 1
1 1 10
10 2 5
1 2 3

输出

12

设计分析

结构体数组BiNode sub[100]来存储各个结点,用parent,rchild,lchild记录父子结点的下标,关联起来。若为-1,则没有关联的结点。

本质上是利用了动态规划的方法,有些地方结合到了遍历的方法。函数PostOrderComp,PostOrder函数为后序遍历,PreOrder函数为先序遍历,Comp函数则为动态规划。

先用PreOrder函数先序遍历找出距离根节点距。

再用PostOrder函数后序遍历找出总运费和权值。

最后用PostOrderComp函数后序遍历并且调用里面的Comp函数比较出在各处设立独立服务机构的运费,来找出最小转移费用。

由于输入的数据较长,所以用文件输入,但是输出只有一个数据,所以直接黑框输出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值