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);
}