题目链接:https://projecteuler.net/problem=45
题意:
Pn=n(3n−1)2
,满足这个通项的数,pi pj,如果 pi pj 的和差也在这个通项中,则求出最小的 pi-pj
思路:
题目很简单的,最主要的问题是,如何确定上界,上界过大时间运行比较长。
先不考虑上界问题:
1.求pi,求pj
2.判断pi+pj,pi-pj是否在通项中
3.求出最小的差值
当然可以自己设置一个很大的数来作为上界。
那么,可以根据 Pn=n(3n−1)2 来确定D=pi-pj的最小值所满足的条件吗?
根据设置上界的方法,我发现这个最小的D就是第一个D,反过来说就是随着n的增大,D是会变大,也就是差值变大。
下面考虑
P(n+1)−P(n)=3n+1
,当n很大时候,相邻两个数的值是
3n+1
,比如:n=100万,差值就是300万,然而这个两个数所在的坐标斜率也是三百万。这个很大了。。。
画下图看看
这个是x和y的散点图,有一万个点,所有看着像是线了,根据这个图可以看到是上升的趋势,仔细看y轴1.5e8,x轴最大才是1W,已经很大了。
下面的图是相邻两个点的斜率,在1000时的斜率是30000
根据上面两点可以知道,相邻连续的两个点的差值随着n的增加而增大,若不是相邻的两个点,则差值会更大,问题让我们求得是最小的差值,则最小的差值就是第一个差值。
所有只需求出第一个满足条件的差值。
Java代码:
package projecteuler41to50;
import java.util.Date;
class level44{
void solve2(){
int minD=9999999;
int D=0;
for(int i=2;;++i){
for(int j=1;j<=i;j++){
int pi=getPentagonal(i);
int pj=getPentagonal(j);
// pj<pi
if(isPentagonal(pj+pi) && isPentagonal(pi-pj)){
D=pi-pj;
if(D<minD){
minD=D;
System.out.println(minD);
return;
}
}
}
}
}
void solve(){
int Max_Value=3000;
int minD=9999999;
int D=0;
for(int i=1;i<=Max_Value;++i){
for(int j=i+1;j<Max_Value;j++){
int pi=getPentagonal(i);
int pj=getPentagonal(j);
// pj>pi
if(isPentagonal(pj+pi) && isPentagonal(pj-pi)){
D=pj-pi;
if(D<minD){
minD=D;
System.out.println(minD);
return;
}
}
}
}
System.out.println(minD);
}
int getPentagonal(int index){
return index*(3*index-1)/2;
}
boolean isPentagonal(int num){
int delt=1+24*num;
if(isSquare(delt)){
int member=(int) (1+Math.sqrt(delt));
if(member%6==0 && member/6>0)
return true;
}
return false;
}
boolean isSquare(int num){
int n=(int) Math.sqrt(num);
if(n*n==num)
return true;
return false;
}
}
public class Problem44 {
public static void main(String[] args){
Date beginTime=new Date();
new level44().solve2();
Date endTime=new Date();
Long Time=endTime.getTime()-beginTime.getTime();
System.out.println("Time="+Time/1000+"秒"+Time%1000+"毫秒");
}
}
solve 是手工设置的上界+第一个D
solve2是直接根据第一个D求得
结果:
5482660
Time=0秒37毫秒
由于上界设成3000,两个运行时间差不多的。
此时对于的i,j是:1020,2167
Python代码:
from time import time
import math
def getPentagonal(index):
return index*(3*index-1)/2
def isPentagonal(num):
index=(math.sqrt(24*num+1)+1)/6
if index==int(index):
return True
return False
t1=time()
for i in range(2,3000):
for j in range(1,i):
plus=getPentagonal(i)+getPentagonal(j)
minus=getPentagonal(i)-getPentagonal(j)
if isPentagonal(plus) and isPentagonal(minus):
print minus
t2=time()
elapsed = t2 - t1
print(str(round(elapsed, 5)) + " seconds")
结果:
5482660.0
15.122 seconds
根据Java程序写的,,,上面的Java程序判断了最小的D,其实不需要的,因为第一个D就是结束了。