题目描述:
有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;
}
// 存在多种节点状态可能性,只记录了一种
}