鱼C论坛

 找回密码
 立即注册
查看: 3232|回复: 9

题目67:使用高效算法找到三角形中的最大和。

[复制链接]
发表于 2015-10-14 15:43:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 欧拉计划 于 2015-10-14 15:45 编辑
Maximum path sum II

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

QQ20151014-4@2x.png

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom in triangle.txt (right click and 'Save Link/Target As...'), a 15K text file containing a triangle with one-hundred rows.

NOTE: This is a much more difficult version of Problem 18. It is not possible to try every route to solve this problem, as there are QQ20151014-5@2x.png altogether! If you could check one trillion QQ20151014-6@2x.png routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)

题目:

从以下三角形的顶端开始,向下一行的相邻数字移动,从顶端到底端的最大总和是 23 。

QQ20151014-4@2x.png

也就是 3 + 7 + 4 + 9 = 23。

p067_triangle.txt (14.79 KB, 下载次数: 84) (右键另存为)是一个文本文件,包含了一个一百行的三角形,找出这个三角形中从顶到底的最大和。

注意:这是题目 18 的更难的一个版本。穷举每一种可能的路径是不可行的,因为一共有 QQ20151014-5@2x.png 条可能的路径。就算每秒钟能处理 QQ20151014-6@2x.png 条路径,也需要 200 亿年来处理完所有的路径。存在一个高效的方法来处理这道题。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-9-25 01:34:05 | 显示全部楼层
本帖最后由 永恒的蓝色梦想 于 2020-7-2 18:48 编辑
7273
[Finished in 0.2s]

lst =[
['59'],
...,
['23','33','44','81','80','92','93','75','94','88','23','61','39','76','22','03','28','94','32','06','49','65','41','34','18','23','08','47','62','60','03','63','33','13','80','52','31','54','73','43','70','26','16','69','57','87','83','31','03','93','70','81','47','95','77','44','29','68','39','51','56','59','63','07','25','70','07','77','43','53','64','03','94','42','95','39','18','01','66','21','16','97','20','50','90','16','70','10','95','69','29','06','25','61','41','26','15','59','63','35']]

dic = {'00':0,'01':1,'02':2,'03':3,'04':4,'05':5,'06':6,'07':7,'08':8,'09':9}
lstnew = lst[:]
for x in range(100):
        for j in range(x+1):
                if lst[x][j] == '00' or lst[x][j] == '01' or lst[x][j] == '02' or lst[x][j] == '03' or lst[x][j] == '04' or lst[x][j] == '05' or lst[x][j] == '06' or lst[x][j] == '07' or lst[x][j] == '08' or lst[x][j] == '09':
                        lstnew[x][j] = dic[lst[x][j]] 
                else:
                        lstnew[x][j] = int(lst[x][j])
for y in range(1,100):
        for z in range(y+1):
                if z == 0:
                        lstnew[y][z] += lstnew[y-1][z]
                elif z == y:
                        lstnew[y][z] += lstnew[y-1][z-1]
                elif lstnew[y-1][z-1] < lstnew[y-1][z]:
                        lstnew[y][z] += lstnew[y-1][z]
                else:
                        lstnew[y][z] += lstnew[y-1][z-1]
print (max(lstnew[99]))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-1 10:33:29 | 显示全部楼层
另外一种,最优化求解的方法(可以适用多路径最优求解):
#coding:utf-8
#initiate:
file=open('triangle.txt')
f=file.read()
file.close()
s=f.split('\n')
triangle = [[]*(i+1) for i in range(100)]
for i in range(100):
    triangle[i]=s[i].split()
for i in range(100):
    for j in range(i+1):
        triangle[i][j]=int(triangle[i][j])
#print (triangle)
visited = [[False]*(i+1) for i in range(100)]
dp = [[0]*(i+1) for i in range(100)]
move = [(1,0),(1,1)]
checklist = [(0,0)]
dp[0][0] = 59

#define method to search the best way:
def findway(x,y):
        if not visited[x][y]:
                visited[x][y] = True
                for m in move:
                        nx,ny = x+m[0],y+m[1]
                        if 0<=nx<100 and 0<=ny<=nx:
                                dp[nx][ny] = max(dp[x][y]+triangle[nx][ny],dp[nx][ny])
                                checklist.append((nx,ny))

#max9999 is the max price to go:
max9999 = 0

#repeat again and again until the max is stable, that's the answer.
while True:
        for i in range(len(checklist)):
                findway(checklist[i][0],checklist[i][1])
        if len([(j,k) for j in range(100) for k in range(j) if not visited[j][k]]) == 0:
                visited = [[False]*(i+1) for i in range(100)]
                checklist = [(0,0)]
                if max9999 < max(dp[99]):
                        max9999 = max(dp[99])
                else:
                        print (max9999)
                        break
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-24 10:30:36 | 显示全部楼层
# encoding:utf-8
# 计算三角形最长路径
from time import time
def readFile():
    data = []
    with open('p067_triangle.txt') as f:
        for line in f:
            tmp = [int(x) for x in str(line).replace('\n', '').split(sep=' ')]
            data.append(tmp)
    return data        
def euler067():
    data = readFile()
    for i in range(len(data) - 2, -1, -1):
        for j in range(0, len(data[i])):
            if data[i][j] + data[i + 1][j] > data[i][j] + data[i + 1][j + 1]:
                data[i][j] = data[i][j] + data[i + 1][j]
            else:
                data[i][j] = data[i][j] + data[i + 1][j + 1] 
    print(data[0][0])          
if __name__ == '__main__':
    start = time() 
    euler067()
    print('cost %.6f sec' % (time() - start))

7273
cost 0.017002 sec
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-5 16:20:20 | 显示全部楼层
data67.csv中数据的格式:
59
73,41
52,40,09
26,53,06,34
10,51,87,86,81
61,95,66,57,25,68
90,81,80,38,92,67,73
30,28,51,76,81,18,75,44
……
import csv

nums = []
with open('data67.csv') as f:
    reader = csv.reader(f)
    for row in reader:
        nums.append(row)

list1 = []
i = len(nums)-1
# 先处理最后一行,选择相邻两个数中大的那个,将其位置、数值放入list1列表中
for j in range(i):
    a = nums[i][j]
    b = nums[i][j+1]
    if a > b and [i,j,a] not in list1:
        list1.append([i,j,a])
    elif b > a and [i,j+1,b] not in list1:
        list1.append([i,j+1,b])

# 从倒数第二行开始,依次向上处理
while i > 0:
    dict1 = {}
    i = i-1
    # 将list1中每个数字的上一行的相邻两个(或一个)数字加到字典dict1中
    for each in list1:
        j = each[1]
        if j == 0:          # 处理每行处于第一列的数字
            dict1.setdefault((i,j),[]).append(int(nums[i][j])+int(each[2]))
        elif j == i+1:      # 处理每行处于最后一列的数字
            dict1.setdefault((i,j-1), []).append(int(nums[i][j-1])+int(each[2]))
        else:               # 处理中间的数字,由于中间的数字在上一行都会对应两个相邻数字,所以要增加一种情况
            dict1.setdefault((i, j), []).append(int(nums[i][j])+int(each[2]))
            dict1.setdefault((i, j - 1), []).append(int(nums[i][j-1])+int(each[2]))
    # 将字典转换为列表,并选择较大的那个数值
    list1 = []
    for each in dict1:
        list1.append([each[0], each[1], max(dict1[each])])
print(list1[0][2])


7273
0:00:00.015637
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 11:00:55 | 显示全部楼层
本帖最后由 fc1735 于 2020-2-21 17:01 编辑
from functools import reduce
f = open('67.txt')
t = f.read()
t = list(map(lambda x: list(map(lambda y: int(y), x.split())),
      filter(lambda x: len(x) != 0, t.split('\n'))))

print(max(reduce(lambda x, y: list(map(lambda a, b: a + b, map(max, [0] + x, x + [0]), y)), t)))
https://github.com/devinizz/project_euler/blob/master/page02/67.py
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-5 10:19:46 | 显示全部楼层
7273

Process returned 0 (0x0)   execution time : 0.049 s
Press any key to continue.
动态规划(dp)经典题,状态转移方程为

                               
登录/注册后可看大图
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

const int M = 100 + 5;
int a[M][M];
int opt[M][M];

int dp(int i,int j){
  if (opt[i][j] >= 0) return opt[i][j];
  if (i == 100-1) return opt[i][j] = a[i][j];
  return opt[i][j] = a[i][j] + max(dp(i+1,j),dp(i+1,j+1));
}

int main(){
  freopen("i.in","r",stdin);
  memset(opt,-1,sizeof(opt));

  for (int i = 0;i < 100;i++){
    for (int j = 0;j <= i;j++){
      cin >> a[i][j];
    }
  }

  cout << dp(0,0) << endl;
  return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-1 18:02:00 | 显示全部楼层
C++
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
using vecus = vector<unsigned short>;


unsigned int max(const vecus& v) {
    unsigned int result = 0;

    for (auto i : v) {
        if (i > result) {
            result = i;
        }
    }

    return result;
}


void scan(ifstream& file, vecus& v, size_t count) {
    unsigned short t;

    for (size_t i = 0; i < count; i++) {
        file >> t;
        v[i] = t;
    }
}


void add(const vecus& a, vecus& b) {
    size_t i;
    b[0] += a[0];

    for (i = 1; i < a.size(); i++) {
        b[i] += max(a[i], a[i - 1]);
    }

    b[i] += a[i - 1];
}


int main() {
    ios::sync_with_stdio(false);

    ifstream file("C:\\Users\\WWW\\Desktop\\0\\p067_triangle.txt");
    constexpr static size_t N = 100;
    vecus a(N), b(N);
    scan(file, b, 1);


    for (size_t line = 2; line <= N; line++) {
        swap(a, b);
        scan(file, b, line);
        add(a, b);
    }


    cout << max(b) << endl;
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-8 13:33:23 | 显示全部楼层
#include <iostream>
using namespace std;
#define max(x,y) ((x)>(y)?(x):(y))
int Array[]={
#include "p067_triangle.txt"
};
#define width 100
void setmax(int i,int j)
{
    if(j == 0)
        Array[i*(i+1)/2+j] += Array[i*(i-1)/2+j];
    else if(j == i)
        Array[i*(i+1)/2+j] += Array[i*(i-1)/2+j-1];
    else
        Array[i*(i+1)/2+j] += max(Array[i*(i-1)/2+j],Array[i*(i-1)/2+j-1]);
}
int main()
{
    for(int i=1;i<width;i++)
        for(int j=0;j<=i;j++)
            setmax(i,j);
    int maxum = 0;
    for(int i=width*(width-1)/2+0;i<width*(width-1)/2+width;i++)
        if(maxum<Array[i])
            maxum = Array[i];
    cout << maxum;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-14 20:43:30 | 显示全部楼层
import time as t

start = t.perf_counter()

with open('C:/Users/50598/Desktop/p067_triangle.txt', 'r') as f:
    file = f.read().splitlines()
    nums = []
    for each_row in file:
        nums.append([int(each_num) for each_num in each_row.split()])

for i in range(len(nums) - 2, -1, -1):
    for j in range(i + 1):
        if nums[i + 1][j] > nums[i + 1][j + 1]:
            nums[i][j] += nums[i + 1][j]
        else:
            nums[i][j] += nums[i + 1][j + 1]

print(nums[0][0])
print("It costs %f s" % (t.perf_counter() - start))


7273
It costs 0.002033 s
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 17:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表