project euler 解题

project euler 3:Any integer greater than 1 is either a prime number, or can be written as a unique product of prime numbers (ignoring the order).

每一个数都能表示成质数的乘积。

const long numm = 600851475143;
long newnumm = numm;
long largestFact = 0;
 
int counter = 2;
while (counter * counter < newnumm) {
    if (newnumm % counter == 0) {
        newnumm = newnumm / counter;
        largestFact = counter;
    } else {
        counter++;
    }
}
if (newnumm > largestFact) { // the remainder is a prime number
    largestFact = newnumm;
}


project euler 4 (回文即反转之后数仍不变)


project euler 5(计算能整除1到20的最小的数,可以用gcd求出最小公约书,然后从2到20开始计算,出去公约数)。


project euler 10(计算

我觉得这个方法不错,用bitset,先每位置1,假设全为质数,然后一个一个的置0,以质数的2倍开始置0,以该质数递增。如4,6,8置0,然后6,9置0,一直循环置0,直到其他为1的全为质数。

#include [lt]iostream[gt]
#include [lt]bitset[gt]

using namespace std;

int main()
{
   bitset[lt]1000000[gt] Sieve;
   __int64 sum = 0;
        
   Sieve.flip();      // Set all bits to 1
   Sieve[0].flip();   // Set 0 and 1 to not prime
   Sieve[1].flip();

   // Check all nos from 2 to 1 million
   for(long i = 2; i < 1000000; ++i)
   {
      if( ! Sieve[i] )   // If marked not prime
         continue;      // return to head of loop
      else
         // Set all multiples as not prime
         for(long j = 2*i; j < 1000000; j += i)
            Sieve[j] = 0; 
   }

   for(long i = 2; i < 1000000; ++i)
      if( Sieve[i] )   // Add all nos with bit set
         sum += i;

   cout << "\nThe sum is : "  << sum << endl;

   return 0;
}



project euler 12(求第一个拥有500个因子的triangle number)

每个数都能表示为N个质数的乘积。

求因子数

private int NumberOfDivisors(int number) {
    int nod = 0;
    int sqrt = (int) Math.Sqrt(number);
 
    for(int i = 1; i<= sqrt; i++){
        if(number % i == 0){
            nod += 2;
        }
    }
    //Correction if the number is a perfect square
    if (sqrt * sqrt == number) {
        nod--;
    }
 
    return nod;
}

Any number N is uniquely described by its prime factorisation

Where pn is the a distinct prime number, an is the exponent of the prime and K is the set of all prime numbers less than or equal to the square root of N.  Taking any unique combination of the prime factors and multiplying them, will yield a unique divisor of N. That means we can use combinatorics to determine the number of divisors based on the prime factorisation. The  prime pncan be chosen 0,1,…,an times. That means in all we can choose pn in an+1 different ways.

The total number of divisors of N , D(N) can be expressed as

其中an为每个质数的指数。即得以前计算因子数的函数。

private int PrimeFactorisationNoD(int number, int[] primelist) {
    int nod = 1;
    int exponent;
    int remain = number;
 
    for (int i = 0; i < primelist.Length; i++) {
        // In case there is a remainder this is a prime factor as well
        // The exponent of that factor is 1
        if (primelist[i] * primelist[i] > number) {
            return nod * 2;
        }
 
        exponent = 1;
        while (remain % primelist[i] == 0) {
            exponent++;
            remain = remain / primelist[i];
        }
        nod *= exponent;
 
        //If there is no remainder, return the count
        if (remain == 1) {
            return nod;
        }
    }
    return nod;
}

project euler 14 (Which starting number, under one million, produces the longest chain?

n  n/2 (n is even) n  3n + 1 (n is odd)))

用caching可以减少运行时间,从小到大查找,cache都记录了,每个数到1的步数,所以当数小于自己时,可以用cache查处步数,直接算出。

代码如:

for (int i = 2; i <= number; i++) {
    sequence = i;
    int k = 0;
    while (sequence != 1 && sequence >= i) {//等于1或小于自己时停止(因为小于自己的数的步数都已经算出来)
        k++;
        if ((sequence % 2) == 0) {
            sequence = sequence / 2;
        } else {
            sequence = sequence * 3 + 1;
        }
    }
    //Store result in cache利用cache算出步数(cache[1] = 1)
    cache[i] = k + cache[sequence];
 
    //Check if sequence is the best solution
    if (cache[i] > sequenceLength) {
        sequenceLength = cache[i];
        startingNumber = i;
    }
}

project euler 15(动态规划题)

How many such routes are there through a 2020 grid?

 project euler 解题_第1张图片

递加上去,直到顶点


project euler 17(计算letters 1到1000用英文表示)

可以用笔算

 Numbers 1-9

There is no particular pattern in the first numbers, so all we can do is spell them out and count them.

3 + 3 + 5 +4 + 4 +3 +5 +5 +4 = 36

 Numbers 10-19

There is also too little pattern in the next 10 numbers that I want to make a deal out of it, so if we count those as well we get

3 + 6 + 6 + 8 + 8 + 7 + 7 + 9 + 8 + 8 = 70

 Numbers 20-99

Now a pattern starts emerging. For each period of ten numbers, we have a prefix 10 times and then the sequence 1-9, which we have already counted.  So we need to figure out how many letters the tens contain and add 8*36.

10*(6 + 6 + 5 + 5 + 5 + 7 + 6 + 6) + 8*36 = 748

So if we sum that up the number 1-99 will contain 36 + 70 + 74 8= 854 letters

 Numbers 100-999

We will use sort of the same trick here.

If we look at one hundred and twenty two (122) and  four hundred and fifty three (453). We will see that the number 1-9 is prepended, then comes the words “hundred and” (10 letters), and last comes a number between 1 and 99.  Whole hundreds such as two hundred (200) are a special case where you have the numbers 1-9 followed by “hundred” (7 letters).

If we break it down we have the numbers 1-9 occurring 100 times each. => 36*100 = 3600

1-99 occurring 9 times => 9*854 = 7686

We have “hundred” occurring 9 times with 7 letters. => 7*9 = 63

We have “hundred and” occurring 9*99 times with 10 letters => 9*99*10 = 8910

So in total we have

3600 + 7686 + 63 + 8910= 20259 +11


project euler 18(动态规划题)

3
7 4
2 4 6

8 5 9 3

底层往上加。

3
7 4
10 13 15


3
20 19

project euler 31How many different ways can £2 be made using any number of coins?2英镑可以有多少种组合情况,用1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p))(动态规划题)

下图表示5p的组合过程。先是初始化0的组合个数为1。然后从1开始计算。1 - 1 = 0,加上0 的组合个数
0 1 2 3 4 5
1 1 0 0 0 0
然后是2,3,4,5有1的组合个数,结果如下图
0 1 2 3 4 5
1 1 1 1 1 1
然后是有2组合的情况,如下图。先从2自己开始。2-2 = 0,加上0的组合个数,2之前的组合个数为1,现在则为2
0 1 2 3 4 5
1 1 2 1 1 1
然后是3有2的组合个数
0 1 2 3 4 5
1 1 2 2 1 1
然后是4,
0 1 2 3 4 5
1 1 2 2 3 1
然后是5,5- 2 = 3 ,3的组合个数为2,则加2,之前为1,则为3.
0 1 2 3 4 5
1 1 2 2 3 3
5的话还有自己本身,则为4.(因为只有1,2,5,三种钱,所以中减1,2,5)。
这样可以类推到 10p, 20p, 50p, £1 (100p) and £2 (200p)的情况。即10,20,50,100,200.(其中的6,7,8,9也都要计算,所有<=200的数都要计算,只是减的时候,只用减 1, 2, 5, 10, 20, 50, £1 (100) and £2 (200) )代码如下,
int target = 200;
int[] coinSizes = { 1, 2, 5, 10, 20, 50, 100, 200 };
int[] ways = new int[target+1];
ways[0] = 1;
 
for (int i = 0; i < coinSizes.Length; i++) {
    for (int j = coinSizes[i]; j <= target; j++) {
        ways[j] += ways[j - coinSizes[i]];
    }
}

project euler 21(Evaluate the sum of all the amicable numbers under 10000.)(amicable number  For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.)


计算公式

  ,最后当p*p >n时,t(n) *= (n + 1),即左边等式

两个互质的数:


计算因子和代码:(因为不包含数本身,最后要减去)

private int sumOfFactorsPrime(int number, int[] primelist) {
    int n = number;
    int sum = 1;
    int p = primelist[0];
    int j;
    int i = 0;
 
    while (p * p <= n && n > 1 && i < primelist.Length) {
        p = primelist[i];
        i++;
        if (n % p == 0) {
            j = p * p;
            n = n / p;
            while (n % p == 0) {
                j = j * p;
                n = n / p;
            }
            sum = sum * (j - 1) / (p - 1);
        }
    }
 
    //A prime factor larger than the square root remains
    if (n > 1) {
        sum *= n + 1;
    }
    return sum - number;
}

project euler 64 求循环周期是奇数的平方根的根数N<=10000

有公式可以计算,是一个迭代公式:
m_0=0\,\!
d_0=1\,\!
a_0=\left\lfloor\sqrt{S}\right\rfloor\,\!
m_{n+1}=d_na_n-m_n\,\!
d_{n+1}=\frac{S-m_{n+1}^2}{d_n}\,\!
a_{n+1} =\left\lfloor\frac{\sqrt{S}+m_{n+1}}{d_{n+1}}\right\rfloor =\left\lfloor\frac{a_0+m_{n+1}}{d_{n+1}}\right\rfloor\!.
其中,要求的就是an,计算an的 循环周期,是奇数就是要求的,计数加1.
循环结束的条件是,an != 2*a0 当等于时,表示进入下一个周期了。其中还要注意的是,如果a0是S的平方根,则直接跳过,这个数没有循环周期后缀。也不适用于这些公式。

project euler 68计算下图能表示的最大16位数(其中每条直线上的和必须相等,即012,324,546,768,981上数字之和必须相等)

project euler 解题_第2张图片 照这顺序,0~9表示存储在数组中的位置,到时候输出就是012324654168981上对应的数字,因为有一个10,所以能有16位数字。
实现的话,还是用排序,用那个0123456789慢慢递增的排序来。在Projcet euler24中有实现过。然后排一次序后计算一次是否符合题目要求(每直线上和都相等),然后在判断是否是最大值,即大于当前最大值。
C++中可以用vector的比较< ,>,其实和string的比较是一个意思(一直没注意到),这样不用把大整数计算出来,直接比较,最后一个个打印出来就可以了。

project euler 69φ(n) 表示小于n,且与n为互质关系数的个数,求n  1,000,000时,n/φ(n)

φ(n) 的公式为,

,有此公式可以用来计算问题,比较简单。其中分母中p表示n中因子中的质数
Where p|n  means all the prime factors p of n.
则此题,当n的因子中的质数数达到最大是,则值最小,即n为从2开始到X质数的乘积,直到大于n。

project euler 70Find the value of n, 1  n  107, for which φ(n) is a permutation of n and the ratio n/φ(n) produces a minimum.要求φ(n)是n的一个排序序列,且n/φ(n)最小 

 we are looking for a number with as few and as large distinct prime factors as possible。So

The obvious best choice would be to find a prime number close to 10.000.000. However, that is not possible since a prime must end in 1,3,7,9 and φ(n) = n-1 would only change the last digit. So they cannot be permutations of each other.一个数的话,不可能会出现φ(n)和n会是同一个排序序列。

The next best thing is two distinct prime factors where each is close to .  So if we just search number which are products of primes between 2000 and 5000 then there should be a good chance that we hit the one we are looking for.

公式:(表示n为p1*p2,两个质数之积)

We can multiply phi with  and with  and get

Since  we get

We can multiply  and  into the fractions and get

project euler 71By listing the set of reduced proper fractions for d  1,000,000 in ascending order of size, find the numerator of the fraction immediately to the left of 3/7,求分母d小于100万(分式<1)的数中,最左接近(小于中最大)3/7的数

根据等式

可以推出
     即得

其中,p/q是当前在求的分式,a/b是上限,即3/7.q是从100万开始递减

还有


其中r/s是当前存的最接近a/b的分式,如果满足上述等式,用p,q替换r,s。

project euler 72  (How many elements would be contained in the set of reduced proper fractions for d  1,000,000?分子与分母互质,即求是简化的分式的个数)

还是这个公式求出<=n的所有数的值,即是i值的所有简化分式,所以最后只要把<=n的所有数的分式个数相加即可,但其中有个效率的问题,因为如果是一个一个计算的话,有很多质数都要被重复计算 [左值*(1-1/p)],这得花不少时间。下面有一个方法,保证每个质数的分式计算只算一次。这个方法在Project Euler 10中提到过。
即把所有包含质数因子的数都算一次乘积,然后以i递增算(这样就把包含质数因子i的所有数都算了一次乘积,得出一个左值,供该数含有的下一个质数因子计算),即 phi[j] = phi[j] / i * (i - 1);其中phi[j]为计算后的左值,即上述公式的i*II(1 - 1/p)式子变形为i /p * (p - 1)其中i即为上式的phi[j]。p即为i。这样每个质数就不会被重复计算。效率比较高。代码为

int limit = 1000000;
int[] phi = Enumerable.Range(0, limit+1).ToArray();
long result = 0;
for(int i = 2; i <= limit; i++){
    if (phi[i] == i) {
        for (int j = i; j <= limit; j += i) {
            phi[j] = phi[j] / i * (i - 1);
        }
    }
    result += phi[i];
}

project euler 73(求序列中1/3与1/2中间的个数)

Farey Sequences(法雷序列)

其中a/b 为下限(开始为1/3,即前一值,之后替换为c/d),c/d为上限(开始为4000/11999,下一值,之后替换为e/f,最终为1/2)。e/f为中间的值。n为序列长度。

project euler 74 ( 求How many chains, with a starting number below one million, contain exactly sixty non-repeating terms?)

先把0到9的阶乘存于数组中,便于计算和节省时间。

用缓存,保存已经计算过到重复数据的数量,算出阶乘和后判断是否已经计算。其中的实现中list可以用vector替换(set其中存储是有序的,不能用于替换list,即不是按顺序存放,是按从小到大排序的)

int limit = 1000000;            
int result = 0;
int[] seqlengths = new int[limit+1];
seqlengths[169] = 3;
seqlengths[363601] = 3;
seqlengths[1454] = 3;
seqlengths[871] = 2;
seqlengths[45361] = 2;
seqlengths[872] = 2;
seqlengths[45362] = 2;
 
for (int i = 1; i <= limit; i++) {
    int n = i;                
    int count = 0;
    List seq = new List();
    seq.Add(0);
                 
    while (seq[seq.Count-1] != n) {                    
        seq.Add(n);
        n = FacSum(n);
        count++;
 
        if(n <= limit && seqlengths[n] > 0){
            count += seqlengths[n];
            break;
        }
    }
    if (count == 60) result++;
 
    for (int j = 1; j < seq.Count; j++) {
        if (seq[j] <= limit) seqlengths[seq[j]] = count;                    
        count--;
    }
}

project euler 76(How many different ways can one hundred be written as a sum of at least two positive integers?100可以被至少两个正数表示的情况有多少种?)(动态规划题)

此题类似project euler 31.其图表示的比较清楚。这里只是每个数都要加减。初试值0的个数为1,然后依次相减,直到100为止。即如1可以有自己组成,2可以由自己和两个1,3则可以有2 ,1;1,1,1;还有自己组成。详情见project euler 31的图过程。(就是减去一个数,然后看得的结果有多少中组合情况,加上他的组合情况,把每个数都减过,然后加了其组合情况后,就是该数自己的组合情况。)

project euler 77(What is the first value which can be written as the sum of primes in over five thousand different ways?第一个可以有质数组成的,有5000以上种组合方法的数)(动态规划题)


这题和之前的project euler 31,76很类似。就是用动态规划的方法,从2开始动态计算每个数的组合个数,如2就一种情况,5则可以用2,3,还有5本身,2种情况。、
方法即初始化0的组合个数为1,1的组合个数为0,然后从质数2,开始,以后依次取更大的质数,所取的数就是以当前质数为初始值,一次相加到最大值,每次就是把当前数减去当前质数,得出的结果即为需要组合的数,然后取其组合个数相加,得当前的组合个数。依次递增相减。当所有质数都遍历过一遍时,即已经计算了所有数的组合情况。
此时,只要从2开始递增查找其中>5000的值即可。(过程用图表示比较直观,可以参照project euler 31 和76题)。

project euler 78(Find the least value of n for which p(n) is divisible by one million.找到可以被一百万整除的p(n)(动态规划题)

 p(5)=7.

OOOOO
OOOO   O
OOO   OO
OOO   O   O
OO   OO   O
OO   O   O   O
O   O   O   O   O
圈圈代表的是硬币,其实和76是一个意思。。。
这题其实和76题差不多,只是会出现溢出的问题,后面前的情况,数都比较大。这就需要每次在计算玩一次组合个数值时,对1000000取模,这样数并没有改变太多,只是编程了1000000的轮回。即只是第多少一百万而已,这个数不用计算出来,只是为了判断最后,算的值是否可以被一百万整除。即可。即当前值是否为0.
这题还有其他很多方法,而且会块很多,有些公式可以用,我就没有在参照了。。我用自己的方法算出来,大概花了26s的样子。

project euler 81(Find the minimal path sum, in matrix.txt (right click and 'Save Link/Target As...'), a 31K text file containing a 80 by 80 matrix, from the top left to the bottom right by only moving right and down.求经过路径的最小和,是从左上到右下,只可以向右和向下移动(如其中红色实心数字的路径。))(动态规划题)



131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 956
805 732 524 37 331
        project euler 解题_第3张图片     project euler 解题_第4张图片 如图,先把331加到左上数字,然后121在下右中选一个选的相加。以此一直加到左上的数,那就是我们要求的结果。

project euler 82(这个题的数据和上面的一样,但是不同的是,同时可以上下右,多了一个方向,还有,它可以是从第一列中任意一个开始,最后一列中任意一个结束,也是求路径最小值)(动态规划题)

这题用动态规划做,理解起来有点困难。
算法:要准备为第一列的每一个数计算一个结果,然后从中选一个最小的,作为最终结果。
首先是从一行的最后一个元素开始计算累加。其中 上和下要分开,计算,因为一列中的一个元素上和下只有一个,不能又上又下。这里把下和右连在一起计算。上额外在计算一次。都是比较最小值,选择一个最小路径。先初始化每行的路径值,用每行的最后一个元素作为初值。
先是处理向下和向右的情况。
1.从第一行(最开始为第0行)倒数第二个元素开始(默认了向右的操作),比较是向右还是下右的路径值更小,然后把路径值赋予小值,一次从上到下比较与赋值。刷新每行的路径值。(是用当前行和上一行比较,上一行的下右)
2。向上的情况。
从倒数第二行倒数第二个元素开始,比较当前向右和上右的路径值,取小者,赋值。依次向上遍历与比较赋值。继续刷新每行的路径值。(是用当前行和下一行比较,下一行的上右)
     当比较了当列元素上下右三个方向,并计算了最小值后,先前移一列,继续回到1.直到处理完第0列的元素。
代码:
int[,] grid = readInput(filename);
int gridSize = grid.GetLength(0);
int[] sol = new int[gridSize];
 
//initialise solution
for (int i = 0; i < gridSize; i++) {
    sol[i] = grid[i, gridSize - 1];
}
for (int i = gridSize - 2; i >= 0; i--) {
    // Traverse down
    sol[0] += grid[0, i];
    for (int j = 1; j < gridSize; j++) {
        sol[j] = Math.Min(sol[j - 1] + grid[j, i], sol[j] + grid[j, i]);
    }
 
    //Traverse up
    for (int j = gridSize - 2; j >= 0; j--) {
        sol[j] = Math.Min(sol[j], sol[j+1] + grid[j,i]);
    }
}

project euler 85(求有最接近200万矩形的矩形的最小面积)


这个是有18个矩形,面积为6;

求有多少个矩形的代码:

int rectangles(int x, int y) {
    int rects = 0;
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < y; j++) {
            rects += (x - i) * (y - j);
        }
    }
    return rects;
}

还有一中优化方法,宽为X,则有X+1个点,从中选2个点,长为Y,则有Y+1个点,从中选2个点,一起组成一个矩形,则可能的情况有

,计算出后为矩形的数量。由公式,可以计算,

即得

所以矩形的数量可以直接用公式X*(X+1)*Y*(Y+1)/4算得。

即代码可以为(其中error为上限值,开始为int的最大值(32位的),当总数大于目标数量target时,减少x,否则增加y)

int error = int.MaxValue;
int closestarea = 0;
int target = 2000000;
 
int x = 2000;
int y = 1;
 
while (x >= y) {
    int rects = x * (x + 1) * y * (y + 1) / 4;
 
    if (error > Math.Abs(rects - target)) {
        closestarea = x * y;
        error = Math.Abs(rects - target);
    }
 
    if (rects > target)
        x--;
    else
        y++;
}

project euler 87(How many numbers below fifty million can be expressed as the sum of a prime square, prime cube, and prime fourth power?求小于5千万的数中,可以表示为都是用质数的平方,立方四次方的和的数的数量)

这个题主要还是要考虑其中可能存在一个数有不同的表示方法,要把重复计算的情况给去掉。还有就是上限的问题 ,所以质数只需要求小于7081的质数,其他两个是370和85就可以了。这样可以省很多时间。生成质数的方法我采用了project euler 10中的方法,用bitset标志每位。这个在数比大的时候,效果应该更明显一点,对于7081,这个方法和直接每个数判断是否是质数的效果差不多。

project euler 89(计算把罗马数字简化为最简式时,节省的字符数(开始题目没看懂,导致代码白写了 - -!))

直接替换字符串"VIIII",“LXXXX”,"DCCCC"."IIII","XXXX","CCCC"到"kk",因为不用实际计算罗马数的结果,直接把前面6种情况都替换成“kk”不影响结果,实现的话,我就是用find,然后在replace,待所有都替换完后,计算减少字符的数量,代码大概如下:(也没找到更好的替换方法)其中,string::npos表示没有找到。

  if((pos = rep.find("LXXXX")) != string::npos)
    {
      rep.replace(pos,5,"kk");
    }

project euler 102(给定3个点的坐标,判断原点是否在该3点包含的区域内)

方法就是先求出该3点组成的三角形的面积,然后计算原点与其中2点组成的面积,然后计算与原点组成的三角形面积之和是否等于3点组成面积,如果是,则表明,原点在其内。

计算面积公式

我觉得还可以用余弦公式来计算由原点到其中2点的角度,如果3个角度之和等于360度,则在其内,不过求角度有写麻烦,要先求出cos的值(用余弦公式

\cos A=\frac{b^2+c^2-a^2}{2bc}
\cos B=\frac{c^2+a^2-b^2}{2ca}
\cos C=\frac{a^2+b^2-c^2}{2ab}
),然后还要转换成角度(可以用cmah中的反余弦函数acos求出)。

project euler 112(求既不是递增数也不是递减数(bouncy)占总数(之前所有数)比例等于99%)、

算百分比可以不用浮点型数,直接用整型,百分比乘以100即可,如100*bouncies < 99*i,其中bouncies为bouncy数数量,i为总数,99为比例

判断是否为bouncy,即判断数既不递增也不递减,用两个bool类型变量即可。





你可能感兴趣的:(project euler 解题)