经典算法题

3.数字三角形最短路径和

动态规划DP解决

我们用 f[i][j]f[i][j] 表示从三角形顶部走到位置 (i, j)(i,j) 的最小路径和。这里的位置 (i, j)(i,j) 指的是三角形中第 ii 行第 jj 列(均从 00 开始编号)的位置。

由于每一步只能移动到下一行「相邻的节点」上,因此要想走到位置 (i, j)(i,j),上一步就只能在位置 (i - 1, j - 1)(i−1,j−1) 或者位置 (i - 1, j)(i−1,j)。我们在这两个位置中选择一个路径和较小的来进行转移,状态转移方程为:

f[i][j] = min(f[i-1][j-1], f[i-1][j]) + c[i][j]
f[i][j]=min(f[i−1][j−1],f[i−1][j])+c[i][j]

其中 c[i][j]c[i][j] 表示位置 (i, j)(i,j) 对应的元素值。

注意第 ii 行有 i+1i+1 个元素,它们对应的 jj 的范围为 [0, i][0,i]。当 j=0j=0 或 j=ij=i 时,上述状态转移方程中有一些项是没有意义的。例如当 j=0j=0 时,f[i-1][j-1]f[i−1][j−1] 没有意义,因此状态转移方程为:

f[i][0] = f[i-1][0] + c[i][0]
f[i][0]=f[i−1][0]+c[i][0]

即当我们在第 ii 行的最左侧时,我们只能从第 i-1i−1 行的最左侧移动过来。当 j=ij=i 时,f[i-1][j]f[i−1][j] 没有意义,因此状态转移方程为:

f[i][i] = f[i-1][i-1] + c[i][i]
f[i][i]=f[i−1][i−1]+c[i][i]

即当我们在第 ii 行的最右侧时,我们只能从第 i-1i−1 行的最右侧移动过来。

最终的答案即为 f[n-1][0]f[n−1][0] 到 f[n-1][n-1]f[n−1][n−1] 中的最小值,其中 nn 是三角形的行数。


int minimumTotal(int** triangle, int triangleSize, int* triangleColSize) {
    int f[triangleSize][triangleSize];
    memset(f, 0, sizeof(f));
    f[0][0] = triangle[0][0];
    for (int i = 1; i < triangleSize; ++i) {
        f[i][0] = f[i - 1][0] + triangle[i][0];
        for (int j = 1; j < i; ++j) {
            f[i][j] = fmin(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j];
        }
        f[i][i] = f[i - 1][i - 1] + triangle[i][i];
    }
    int ret = f[triangleSize - 1][0];
    for (int i = 1; i < triangleSize; i++)
        ret = fmin(ret, f[triangleSize - 1][i]);
    return ret;
}

1.光纤

考察带权路径和最小的问题
大白话!!翻译一下
构造哈夫曼树!
怎么构造?
用优先队列构造!
看代码!

typedef struct//哈夫曼树的存储表示
{
    int weight;    					//权值
    int parent, lChild, rChild;    	//双亲及左右孩子的下标 
}HTNode, *HuffmanTree;

void Select(HuffmanTree hT, int n, int &s1, int &s2)//选择两个最小节点 
{
    s1 = s2 = 0;
    int i;
    for(i = 1; i < n; ++ i)//选择两个未有双亲的节点 
	{
        if(hT[i].parent == 0)
		{
            if(0 == s1)
			{
                s1 = i;
            }
            else
			{
                s2 = i;
                break;//后面一个for循环的标记 
            }
        }
    }
    if(hT[s1].weight > hT[s2].weight)//确保s1>s2 
	{
        int t = s1;
        s1 = s2;
        s2 = t;
    }
    for(i+=1;i<n;++i)//选择s2即break 故从i+1开始选择两个最小节点 
	{
        if(hT[i].parent==0)
		{
            if(hT[i].weight < hT[s1].weight)
			{
                s2 = s1;
                s1 = i;
            }
			else if(hT[i].weight < hT[s2].weight)
			{
                s2 = i;
            }
        }
    }
}

void CreateHufmanTree(HuffmanTree &hT)//构造哈夫曼树 
{
    int n,m;
    cin>>n;
    m = 2*n - 1;
    hT = new HTNode[m + 1];
	hT[0].weight=m;  // 0号节点用来记录节点数量 
    for(int i = 1; i <= m; ++ i)
	{
        hT[i].parent = hT[i].lChild = hT[i].rChild = 0;//初始化 
    }
    for(int i = 1; i <= n; ++ i)
	{
        cin >> hT[i].weight;    // 输入权值 
    }
    for(int i = n + 1; i <= m; ++ i)//建立过程 
	{
        int s1, s2;
        Select(hT, i, s1, s2);
        hT[s1].parent = hT[s2].parent = i;
        hT[i].lChild = s1; hT[i].rChild = s2;    			//作为新节点的孩子 
        hT[i].weight = hT[s1].weight + hT[s2].weight;    	//新节点为左右孩子节点权值之和 
    }
    
}

int HuffmanTreeWPL_(HuffmanTree hT, int i, int deepth)//递归计算WPL 
{
    if(hT[i].lChild == 0 && hT[i].rChild == 0)
	{
        return hT[i].weight * deepth;
    }
    else
	{
        return HuffmanTreeWPL_(hT, hT[i].lChild, deepth + 1) + HuffmanTreeWPL_(hT, hT[i].rChild, deepth + 1);
    }
}

int HuffmanTreeWPL(HuffmanTree hT)//计算WPL 
{
    return HuffmanTreeWPL_(hT, hT[0].weight, 0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值