我是编码的初学者。我想使用简单的递归和数组来解决以下问题。但我无法将其可视化。我想出了使用链接列表的解决方案。以下是问题和我的解决方法
给定n行整数,使得第i行(
1 <= i <= n
) 包含我的整数。使用以下一组路径规则,找到 具有最大重量的路径。路径遍历规则:
有效路径序列将自上而下,即以第一行中的整数开头,并遍历所有行,只选择一行 每行中的整数。
- 醇>
从第i行中的任何第j个整数,即
row[i][j]
,遍历可以向下(即row[i+1][j]
)或斜向下发生 向右(即row[i+1][j+1]
)。Path的权重是Path中整数值的总和 序列。
示例:
No. of Rows: 5 4 2 9 15 1 3 16 92 41 44 8 142 6 4 8
预期输出:4,2,15,92,142(最大重量为255)
Sol.c
#include<stdio.h>
#include<stdlib.h>
int n,**ar;
struct n
{
int i,j;
int w;
struct n *ptr;
};
struct n* maxweight(int i,int j,struct n* x)
{
struct n* tmp=malloc(sizeof(struct n)),*t1,*t2;
tmp->i=i;
tmp->j=j;
tmp->ptr=x;
tmp->w=ar[i][j];
if(x)tmp->w+=x->w;
if(i==n-1)return tmp;
t1=maxweight(i+1,j,tmp);
t2=maxweight(i+1,j+1,tmp);
if(t1->w>t2->w)return t1;
return t2;
}
int main()
{
int i,j;
struct n * s;
printf("Enter the value of n\n");
scanf("%d",&n);
ar=malloc(n*sizeof(int*));
for(i=0;i<n;i++)
{
ar[i]=malloc((i+1)*sizeof(int));
for(j=0;j<=i;j++)scanf("%d",&ar[i][j]);
}
s=maxweight(0,0,NULL);
printf("MAX WEIGHT is :%d\nPATH: ",s->w);
while(s)
{
printf("%d ",ar[s->i][s->j]);
s=s->ptr;
}
printf("\n");
return 0;
}
如何在没有使用n x n矩阵的链接列表的情况下使用递归来解决这个问题?动态编程是否适用于此问题。
答案 0 :(得分:2)
专注于计算你的前方路径的权重; 不要回头。
首先解决一个简单的边缘情况。假设你做到了最底行。然后没有什么可以追随的;剩下的路径重量为零。
在代码中:
int getWeight(int i, int j)
{
int remaining = 0;
在任何其他行中,您必须做出选择。你应该左转还是右转?由于目前无法知道哪一个最好,你只需要尝试两个方向:
if (i < lastRow)
{
int weightLeft = getWeight(i + 1, j);
int weightRight = getWeight(i + 1, j + 1);
注意我递归地调用了我自己的函数; 盲目信仰,该功能能够为剩余路径提供最佳权重!
尝试了两个方向后,选择最重要的重量:
int best_j = weightLeft > weightRight ? j : j + 1;
现在我们再次走上选定的道路。
remaining = getWeight(i + 1, best_j);
}
这不是很有效,但它有助于收集最佳路径的各个步骤。我将使用一个简单的数组pathColumns
。
pathColumns[i] = j;
最后,我们需要对这些值求和。
return row[i][j] + remaining;
}
要设置整个运动,只需调用该函数,并将顶部单元格的坐标传递给它。出于实际原因,我将所有数组都设为base-0。所以顶部单元格是row[0][0]
。
printf("Optimal weight: %d\n", getWeight(0, 0));
全部放在一起:
#include <stdio.h>
#define n 5
int pathColumns[n] = {0};
int row[n][n] =
{
{4},
{2, 9},
{15, 1, 3},
{16, 92, 41, 44},
{8, 142, 6, 4, 8}
};
int getWeight(int i, int j)
{
int remaining = 0;
if (i < n-1) /* with base-0, the last row is n-1 */
{
int weightLeft = getWeight(i + 1, j);
int weightRight = getWeight(i + 1, j + 1);
int best_j = weightLeft > weightRight ? j : j + 1;
remaining = getWeight(i + 1, best_j);
}
pathColumns[i] = j;
return row[i][j] + remaining;
}
int main()
{
int i;
printf("Optimal weight: %d\n", getWeight(0, 0));
for (i = 0; i < n; i++)
{
int j = pathColumns[i];
printf("(%d, %d) = %d\n", i+1, j+1, row[i][j]);
/* NOTE: +1 is a correction to bring the output back to base-1 */
}
return 0;
}
输出:
Optimal weight: 255
(1, 1) = 4
(2, 1) = 2
(3, 1) = 15
(4, 2) = 92
(5, 2) = 142
我们希望getWeight(0, 0)
返回此金字塔最重的路径。
4 <---- (0, 0) is our starting point
/ \
2 9
/ \ / \
15 1 3
/ \ / \ / \
16 92 41 44
/ \ / \ / \ / \
8 142 6 4 8
递归算法进行两次递归调用。
getWeight(1, 0)
必须获得我们起点下方和左侧的子金字塔最重的路径。getWeight(1, 1)
必须获得我们起点下方和右侧的次金字塔最重的路径。两个次金字塔:
2 <--- (1, 0) 9 <--- (1, 1)
/ \ / \
15 1 1 3
/ \ / \ / \ / \
16 92 41 92 41 44
/ \ / \ / \ / \ / \ / \
8 142 6 4 142 6 4 8
假设getWeight(1, 0)
和getWeight(1, 1)
返回正确的权重(分别为251和244),剩下要做的就是选择最高权重(251)并添加大金字塔的最高值对它(4)。结果是255。
我们所做的是减少一个问题(计算高度为5的金字塔的最大权重),这样我们就可以解决两个较小的问题(计算高度为4的金字塔的最大权重)。以同样的方式,我们可以减少高度4的问题来解决高度3的相同问题。例如,getWeight(1, 1)
将进行两次递归调用getWeight(2, 1)
和getWeight(2, 2)
:
1 <--- (2, 1) 3 <--- (2, 2)
/ \ / \
92 41 41 44
/ \ / \ / \ / \
142 6 4 6 4 8
getWeight(1, 1)
应返回244 = 9 + max(235,55)。
继续这样,我们最终最终解决了高度为1的金字塔的问题。这些是原始金字塔底部的值(8,142,6,4和8)。这里的递归结束了;高度为1的金字塔只不过是一个节点。该节点的值是通过该金字塔的(唯一)路径的权重。