华为机试:节点队列的转发问题

题目描述:

有k个节点的转发队列,每个节点转发能力为m,缓存能力n(表示此节点可立即转发m个包,剩余的缓存,最多缓存n个包再剩余的丢弃,缓存的包在下轮继续转发)。 另外,此队列中某些节点可能因故障需要直接跳过转发,但不会有两个连续故障的节点。

现分两轮操作,第一轮向此队列发送a个数据包让其转发第二轮,直接驱动让缓存的数据包继续转发。
求两轮最后可能收到的最少数据包总个数(如果第二轮缓存仍有数据包,缓存包按丢弃处理)
1<=k<=40
1<=m, n<=1000
1<=a<=1000
例如:有两个节点,节点1(转发能力m:50,缓存能力n:60)和节点2(m:30,n:25),发送包数为120。

解题思路:

递归实现动态规划。
在这里插入图片描述

代码:

#include <iostream>
using namespace std;

struct node
{
	node* pre;
	node* next;
	int outC;  //节点输出能力
	int cacheC; //节点缓存能力
	int errorFlag; //当前节点是否故障,1:不故障,-1:故障,0:不确定
	int currentNum; //当前节点已缓存的数据包数量
};

// 第二轮数据流计算输出
int secondFlow(node *P, int inNum)
{
	int outNum;
	if (P->errorFlag == 1)
	{
		if (inNum + P->currentNum > P->outC)
			outNum = P->outC;
		else
			outNum = inNum + P->currentNum;
	}
	else
		outNum = inNum;

	if (P->next != nullptr)
		outNum = secondFlow(P->next, outNum);
	return outNum;
}

// 递归计算最少输出数据包数量
int flow(node *P, int dataNum)
{
	node *P2;
	int outNum;
	int outNum2;
	// 判断上一节点的状态,若上一节点故障,则当前节点必然不故障(根据题目描述:两个节点不连续故障);
	// 若上一节点无故障或者无上一节点,则当前节点存在两种可能性,先取故障的情况。
	if (P->pre != nullptr)
		if (P->pre->errorFlag==-1)
			P->errorFlag = 1;
	if (P->errorFlag == 0)
		P->errorFlag = -1;
	
	if (P->errorFlag == 1) // 如果当前节点无故障,就不需要比较两种情况
	{
		if (P->outC < dataNum)
		{
			if (P->cacheC >= dataNum - P->outC)
				P->currentNum = dataNum - P->outC;
			else
				P->currentNum = P->cacheC;
			dataNum = P->outC;
		}
		if (P->next == nullptr)
		{
			P2 = P;
			while(P2->pre != nullptr)
				P2 = P2->pre;
			outNum = dataNum + secondFlow(P2, 0); // 到一个节点了,计算第二轮输出(每个节点的状态已经确定,缓存数也已知)加上第一轮输出
		}
		else
			outNum = flow(P->next, dataNum); // 未到最后一个节点,递归
		
	}
	else // 如果当前节点故障,就存在另一种状态,即无故障状态。比较两种情况下的最小输出,取最小的那种情况。
	{
		// 故障情况下的输出 outNum
		if (P->next == nullptr)
		{
			P2 = P;
			while(P2->pre != nullptr)
				P2 = P2->pre;
			outNum = dataNum + secondFlow(P2, 0);
		}
		else
			outNum = flow(P->next, dataNum);
		// 不故障情况下的输出 outNum2
		P->errorFlag = 1;
		if (P->outC < dataNum)
		{
			if (P->cacheC >= dataNum - P->outC)
				P->currentNum = dataNum - P->outC;
			else
				P->currentNum = P->cacheC;
			dataNum = P->outC;
		}
		if (P->next == nullptr)
		{
			P2 = P;
			while(P2->pre != nullptr)
				P2 = P2->pre;
			outNum2 = dataNum + secondFlow(P2, 0);
		}
		else
			outNum2 = flow(P->next, dataNum);
		// 比较两种情况下的输出大小,将小的往回传
		if (outNum2 < outNum)
			outNum = outNum2;
		else
			P->errorFlag = -1;
	}
	return outNum;
}

int main()
{
	const int nodeNum = 2;
	const int outC_cacheC[nodeNum][2] = {50, 60, 30, 25};

    //初始化节点
	node *P = new node;
	node *T;
	for (int i=0; i<nodeNum; i++)
	{
		if (i==0)
		{
			P->pre = nullptr;
		}
		else
		{
			T = new node;
			T->pre = P;
			P->next = T;
			P = T;
		}
		P->currentNum = 0;
		P->errorFlag = 0;
		P->outC = outC_cacheC[i][0];
		P->cacheC = outC_cacheC[i][1];
	}
	P->next = nullptr;

	//计算
	while(P->pre != nullptr)
		P = P->pre;
	int minOut;
	minOut = flow(P, 120);

	while(P->pre != nullptr)
		P = P->pre;
	cout<<"minOut: "<<minOut<<endl;
	cout<<"nodeState: ";
	while (1)
	{
		cout<<P->errorFlag<<';';
		if (P->next != nullptr)
			P = P->next;
		else
			break;
	}
	// 存在多种节点状态可能性,只记录了一种
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值