Algorithm Euler项目#18方法
我正在研究一个Euler项目。特别是#18.Algorithm Euler项目#18方法,algorithm,Algorithm,我正在研究一个Euler项目。特别是#18. 总之,我们的想法是从三角形中找到最大路径: 3 7 4 2 4 6 8 5 9 3 3+7+4+9=23 在阅读本文时,大多数人都表示,这是通过自下而上而不是使用自上而下“贪婪”的算法来正确解决的 我可以理解,自上而下选择你发现的最大值是“短视的”,可能不是整体最大值 但为什么自下而上的方法更好呢? 在我看来,它也有同样的问题 例如,在示例中的三角形中,我们将得到(从底部开始): 9+6+4+3=22
总之,我们的想法是从三角形中找到最大路径:
3
7 4
2 4 6
8 5 9 3
3+7+4+9=23
在阅读本文时,大多数人都表示,这是通过自下而上而不是使用自上而下“贪婪”的算法来正确解决的
我可以理解,自上而下选择你发现的最大值是“短视的”,可能不是整体最大值
但为什么自下而上的方法更好呢?在我看来,它也有同样的问题 例如,在示例中的三角形中,我们将得到(从底部开始):
9+6+4+3=22<23
那么为什么要从自下而上开始呢?采用自下而上的方法可以消除路径,而自上而下只会增加潜在路径 因为您可以更快地消除错误路径,所以广度优先搜索成为最佳解决方案。任何方向的深度优先搜索都是错误的(如您所示),而且速度较慢。使用您的示例,“自下而上”的方法是: 检查最下面一行,可以从每个元素中获得的最多信息是 8,5,9,3 检查下一行,您可以从每个元素中获得的最多信息是(取决于从它向左还是向右): 2+最大值(8,5),4+最大值(5,9),6+最大值(9,3)=10,13,15 所以这是伟大的;我们已经消除了两行,将它们挤压在一起,以一行替换,从而将问题减少到一行
3
7 4
10 13 15
显然,我们可以继续重复这一点。检查下一行,可以从每个元素中获得的最多信息是
7+最大值(10,13),4+最大值(13,15)=20,19
因此,从上面看,你能得到的最多是
3+最大值(20,19)=23
QED.这是一种叫做动态规划的东西 你有这样的三角形:
3
7 4
2 4 6
8 5 9 3
当您从底部移动到顶部时,您可以计算上一次迭代的最佳选择。
在这种情况下,取最后一行8 5 9 3
,并最大化上一行之外的总和
迭代1:
假设您处于last-1
步骤
您有一行246
,让我们迭代一下
从2开始,您可以转到8或5,因此8更好(从2最大化您的结果),因此您可以计算第一和8+2=10
从4开始,您可以选择5或9,因此9更好(将结果从4最大化),因此您可以计算第二个和9+4=13
从6开始,您可以转到9或3,因此9再次更好(将结果从6最大化),因此您可以计算第三个和9+6=15
这是第一次迭代的结束,您得到了sums101315
行
现在你们得到了低维三角形:
3
7 4
10 13 15
现在继续,直到得到一个值,正好是23。自上而下和自下而上之间没有区别。贪婪方法和“前沿”方法之间的区别 贪婪算法不一定能帮到你,因为如果树的最好部分够不着,你就无法恢复。例如:贪婪算法会从上到下选择路径1-3。它将完全错过9点
1
2 3
9 1 1
为了找到真正的最大值,您必须遍历几乎所有的路径
正如所描述的,自下而上的方法没有这个问题。它最多检查n*(n-1)条路径:每个元素2条。然而,将其称为“自下而上”的方法具有误导性
为什么??因为有一种自上而下的方法是等效的。本质上,你有一种“边界”,对边界后面的所有树木都有最好的结果。无论你是向上还是向下移动边界都是次要的。对于上例中的自上而下方法,您可以为每一行计算每个元素的总和及其上方两个最佳总和的最大值:
1
3 4
12 5 5
在自下而上的方法中,为每一行计算每个元素的总和以及下面两个最佳总和的最大值。按相反顺序:
9 1 1
11 4
12
在这两种自上而下和自下而上的方法中,工作几乎是一样的。实际上,你不必从自下而上开始;如果你做得好,你也可以从上到下开始 从金字塔的每一层所发生的事情可以最好地说明它是如何自下而上工作的。这条路一定要在某个点穿过每一层
x
x x
x h x
x y y x
x y y y x
假设它是h
。从允许路径的定义来看,路径只能向下延伸到y
标记的位置,这形成了一个类似于原始的问题-如果我们通过y
s找到一条最大路径,并且整个三角形的最大路径实际上通过h
,它肯定会沿着y
s中的一条最大路径(如果不是,您可以切换较小三角形中的路径部分,得到一条总体上更好的路径)
因此,如果您自上而下地构造算法,计算从当前节点向下的最大路径,您将得到正确的结果(即,最大路径值,从中您可以轻松获得路径本身)
现在,这取O(n)(n表示数字的数目),因为对于每个地方,你只考虑两个路径并使用较低级别的预先计算的值。
实际上,相同的算法可以自上而下实现,只要记住结果,就可以从顶部开始向下递归best_length(node)
{
if(node is terminal)
return value(node)
int m = 0
for(next : lower neighbors of node)
m = max(best_length(next), m)
return m + value(node);
}
另一种自上而下的方法是反向计算。从顶部开始,考虑到每个节点的上部邻居,并获取从该节点顶部结束的路径长度(而不是从该节点向下到底部行的路径)。最后,从最下面一行收集数据,就完成了。这是一个可以用图论解决的问题。对于每个点,您只能移动到它的两个“子节点”(左侧和右侧节点)中的每一个
import sys
def max_sum(i,j):
if i==14:
return a[i][j]
return a[i][j]+max(max_sum(i+1,j),max_sum(i+1,j+1))
a=[]
for i in range(15):
b=list(map(int,sys.stdin.readline().split()))
a.append(b)
print(max_sum(0,0))
import sys
d={}
def max_sum(i,j):
if (i,j) in d:
return d[(i,j)]
if i==99:
return a[i][j]
d[(i,j)]=a[i][j]+max(max_sum(i+1,j),max_sum(i+1,j+1))
return d[(i,j)]
a=[]
for i in range(100):
b=list(map(int,sys.stdin.readline().split()))
a.append(b)
print(max_sum(0,0))
#include <iostream>
using namespace std;
int main()
{
int sum1,sum2;
int A[4][4] = {{3,0,0,0},{7,4,0,0},{3,4,6,0},{8,5,9,3}};
for(int i=2;i>=0;i--){
for(int j=0;j<4;j++){
sum1=A[i][j]+A[i+1][j];
sum2=A[i][j]+A[i+1][j+1];
if(sum1>sum2){
A[i][j]=sum1;
}
else{
A[i][j]=sum2;
}
}
}
cout<<A[0][0]<<endl;
}
static int getTriangle() throws FileNotFoundException, IOException{
File file = new File("/home/rakib/This Pc/programming/problem solving/ProjectEuler/src/projecteuler/euluer17.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
String n;
int i = 0;
int [][] array = new int[15][15];
while((n = br.readLine()) != null){
String [] temp = n.split(" ");
for(int j = 0; j < temp.length; j++){
array[i][j] = Integer.parseInt(temp[j]);
}
i++;
}
for(int j = array.length-2; j >= 0; j--){
int []tempArray = new int [j+1];
for(int k =0; k <= j; k++){
tempArray[k] = array[j][k] + Math.max(array[j+1][k], array[j+1][k+1]);
}
array[j] = tempArray;
}
return array[0][0];
}