Programmeringsutfordring!

Her kan brukere av forum utfordre hverandre med morsomme oppgaver og nøtter man ønsker å dele med andre. Dette er altså ikke et sted for desperate skrik om hjelp, de kan man poste i de andre forumene, men et sted for problemløsing på tvers av trinn og fag.

Moderators: Vektormannen, espen180, Aleks855, Solar Plexsus, Gustav, Nebuchadnezzar, Janhaa

Post Reply
Aleks855
Rasch
Rasch
Posts: 6874
Joined: 19/03-2011 15:19
Location: Trondheim
Contact:

Laga denne lille nøtta etter jeg fant ut at det finnes en tallgruppe som har en litt små-artig egenskap. Få høre hva dere syns! :)

En tallgruppe kalt "narsissistiske tall" har følgende egenskap:

For hvert siffer, opphøy sifferet i antall sifre i tallet, summer dem, og få samme tall som du startet med.


Eksempel:

[tex]153 \ \text{har 3 sifre} \ \rightarrow \ 1^3 + 5^3 + 3^3 = 153[/tex]

Finn det første narsissistiske tallet større enn 100.000.000.

Siden dette kan spores opp på nettet, vis også fremgangsmåte. Gjerne i form av en kodesnutt i valgfritt programmeringsspråk.

(Forvent at programmet ditt bruker et minutt eller to... eller flere, avhengig av hvordan ditt programmeringsspråk kompilerer kode.)

La meg høre hva dere syns om nøtta. Den burde være grei å kode, men jeg forventer ikke at folk skal få den til for hånd :lol:

-Aleks
Image
2357
Lagrange
Lagrange
Posts: 1180
Joined: 07/12-2007 22:08

Hvis man ikke er opptatt av effektivitet, holder det med følgende linjer i Python.

Code: Select all

tall = 100000000

while sum([int(i)**len(str(tall)) for i in str(tall)]) != tall:
    tall += 1

print tall
Så var det det å huske nok syntaks til å lage et program som er effektivt nok til at man orker å kjøre det.
Aleks855
Rasch
Rasch
Posts: 6874
Joined: 19/03-2011 15:19
Location: Trondheim
Contact:

Nesten så man hater Python for å bruke så få linjer. :lol:

Kunne vært interessant hvis du hadde lagt inn en timer som sjekker hvor lang tid den brukte på å finne det første tallet. :)
Image
Aleks855
Rasch
Rasch
Posts: 6874
Joined: 19/03-2011 15:19
Location: Trondheim
Contact:

Min brukte 209 sekunder. Det kan sikkert overgås ganske lett, siden jeg har litt debugging-prints og diverse O(n)-snadder som kanskje ikke er nødvendig.
Image
Gustav
Tyrann
Tyrann
Posts: 4563
Joined: 12/12-2008 12:44

Aleks855 wrote:Min brukte 209 sekunder. Det kan sikkert overgås ganske lett, siden jeg har litt debugging-prints og diverse O(n)-snadder som kanskje ikke er nødvendig.
Hvilket språk brukte du?

Matlab:

Code: Select all

tic
n = 10^8;
k = 0;
while k ~= n
    k = 0;
    n = n+1;
    for i = 0:8
        k = k + mod(floor(n/(10^i)),10)^9;
        if k > n
            break;
        end
    end
end
toc
fprintf('%d \n',n)


Elapsed time is 77.422856 seconds.

146511208
Last edited by Gustav on 18/11-2012 05:06, edited 1 time in total.
Kork
von Neumann
von Neumann
Posts: 527
Joined: 26/07-2011 18:44
Location: Bergen

Laget en raskt, jeg har bare grunnkurs i java så dette er ikke særlig elegant :D :D

Code: Select all

    int[] i = {1,0,0,0,0,0,0,0,0};
    int ii, sum, siffer = i.length;
    do {
      ii = 0; sum = 0;
      for(int j=siffer;j>0;j--) {
        ii+=i[j-1]*Math.pow(10,Math.abs(siffer-j));
        sum+=Math.pow(i[j-1], siffer);
      }
      boolean tallPlussEn = false;
      for(int j=siffer;j>0 && !tallPlussEn;j--) {
        if(i[j-1]!=9) {
          i[j-1]++;
          tallPlussEn=true;
          
          for(int jj=j;jj<siffer;jj++) {
            i[jj]=0;
          }
        }
      }
    } while(sum!=ii);
142 sekunder på en seig bærbar
Mathematics is the gate and key to the sciences.
Gustav
Tyrann
Tyrann
Posts: 4563
Joined: 12/12-2008 12:44

Er jo en grei oppgave. Ligner på project Euler. Kanskje litt for enkel med mindre man setter krav til max kjøretid? Det burde være mulig å få kjøretida ned på et vesentlig lavere nivå.

Oppfølger:

Definisjon: Et positivt heltall n kalles en perfekt digital invariant (PDI) dersom det fins et positivt heltall m slik at summen av sifrene opphøyd i m er lik tallet selv.

F.eks. er [tex]n=4150=4^5+1^5+5^5+0^5[/tex] en PDI med [tex]m=5[/tex].

(Alle narsissistiske tall er også PDI med m=antall siffer i tallet)

Hva er minste PDI større enn [tex]10^7[/tex]?
Emilga
Riemann
Riemann
Posts: 1552
Joined: 20/12-2006 19:21
Location: NTNU

Programmet (Python)

Code: Select all

def strip(n):
    a = []
    while n:
        a.append(n%10)
        n = n/10
    return a

n = 10**7+1
found = 0
while not found:
    a = strip(n)
    i = 1
    b = [x**i for x in a]
    while sum(b) <= n and sum(b) < sum([x**(i+1) for x in a]):
        if sum(b) == n:
            print(n,i)
            found = 1
        i+=1
        b = [x**i for x in a]
    n += 1
returnerer (n,m) = (14459929, 7). Programmet kan nok lages mer effektivt enn dette.
Gustav
Tyrann
Tyrann
Posts: 4563
Joined: 12/12-2008 12:44

Ser bra ut.

Enda en oppfølger:

Definisjon: La en tallfølge [tex]\{H_n\}_{n\in\mathbb{N}\setminus \{0\}}[/tex] være gitt ved at

[tex]H_n = \sum_{i=1}^n \frac{1}{i^2}[/tex] for alle positive heltall n.

Anta at vi skriver alle brøkene i følgen [tex]H_n[/tex] på redusert form, slik at største felles faktor til teller og nevner er 1. (Dersom [tex]H_n=\frac{a}{b}[/tex] så er [tex]gcd(a,b)=1[/tex], a og b er heltall)

Altså er

[tex]H_1 = 1[/tex],
[tex]H_2 = 1+\frac{1}{2^2} = \frac{5}{4}[/tex]
[tex]H_3 = 1+\frac{1}{2^2}+\frac{1}{3^2}=\frac{49}{36}[/tex] osv.

La [tex]W_n[/tex] være definert som telleren til [tex]H_n[/tex].

Altså får vi en heltallsfølge med

[tex]W_1 = 1[/tex]
[tex]W_2 = 5[/tex]
[tex]W_3 = 49[/tex]
osv.

Det første tallet i følgen [tex]\{W_n\}[/tex] som er primisk er derfor [tex]W_2=5[/tex].

Finn de neste 3 tallene i følgen [tex]W_n[/tex] som er primtall.
Emilga
Riemann
Riemann
Posts: 1552
Joined: 20/12-2006 19:21
Location: NTNU

Her har du vært lur! Steinaldermetoden/brute force funker ikke:
Output:

Code: Select all

Leddet 2 har primtalls-teller: (5, 4)
Leddet 7 har primtalls-teller: (266681, 176400)

...
MemoryError
Kode:

Code: Select all

def gcd(a,b):
    # returnerer sfd(a,b)
    d = 1
    for i in range(1,min(a,b)+1):
        if not a%i and not b%i:
            d = i
    return d

def reduser(a):
    #input: touple a tolket som broek
    #output: touple (b,c) lik reduserte broek a
    d = gcd(a[0],a[1])
    b = a[0]/d
    c = a[1]/d
    return (b,c)

def isprime(n):
    # input: heltall n
    # output: 1 hvis n er primsk, 0 hvis n er sammensatt
    for i in range(2,n):
        if not n%i:
            return 0
    return 1

# H[k] er H_k som definert i oppgaveteksten
H = [(1,1),(1,1)]

# Antall primtall W_k funnet.
primtall = 0
# Finn 4 av dem
while primtall <= 4:
    # Legg til neste ledd i foelgen H ved aa benytte seg
    # av siste utregnede H-verdi
    l = len(H)-1
    Hl = H[l]
    Hl1 = (Hl[0]*(l+1)**2 + Hl[1], Hl[1]*(l+1)**2)
    Hl1 = reduser(Hl1)
    H.append(Hl1)
    # Sjekk om telleren er et primtall
    if isprime(Hl1[0]):
        print "Leddet %s har primtalls-teller: %s" % (l+1,Hl1)
        primtall += 1
Gustav
Tyrann
Tyrann
Posts: 4563
Joined: 12/12-2008 12:44

Det er vel isprime-funksjonen din som bør utbedres endel..
Emilga
Riemann
Riemann
Posts: 1552
Joined: 20/12-2006 19:21
Location: NTNU

Ja. Har endret isprime til å bruke at hvis et tall n er samensatt, så har det en faktor som er lavere enn sqrt(n). Bytter også ut range(..) med en while-løkke som bare sammenligner to heltall. Tror det er billigere, men er ikke sikker... Det tar dog fortsatt skrekkelig lang tid, så vet ikke om jeg ender opp med en løsning uansett. :)

Code: Select all

def gcd(a,b):
    # returnerer sfd(a,b)
    d = 1
    i = 1
    while i <= min(a,b)+1:
        if not a%i and not b%i:
            d = i
        i+=1
    return d

def reduser(a):
    #input: touple a tolket som broek
    #output: touple (b,c) lik reduserte broek a
    d = gcd(a[0],a[1])
    b = a[0]/d
    c = a[1]/d
    return (b,c)

def isprime(n):
    # input: heltall n
    # output: 1 hvis n er primsk, 0 hvis n er sammensatt
    i = 2
    while i <= int(n**.5)+1:
        if not n%i:
            return 0
        i+=1
    return 1

# H[k] er H_k som definert i oppgaveteksten
H = [(1, 1), (1, 1)]

#[(1, 1), (1, 1), (5, 4), (49, 36), (205, 144), (5269, 3600), (5369, 3600), (266681, 176400), (1077749, 705600), (9778141, 6350400), (1968329, 1270080), (239437889, 153679680)]

# Antall primtall W_k funnet.
primtall = 0
# Finn 4 av dem
while primtall <= 4:
    # Legg til neste ledd i foelgen H ved aa benytte seg
    # av siste utregnede H-verdi
    l = len(H)-1
    Hl = H[l]
    Hl1 = (Hl[0]*(l+1)**2 + Hl[1], Hl[1]*(l+1)**2)
    Hl1 = reduser(Hl1)
    H.append(Hl1)
    # Sjekk om telleren er et primtall
    if isprime(Hl1[0]):
        print "Leddet %s har primtalls-teller: %s" % (l+1,Hl1)
        primtall += 1
    else:
        print "Leddet %s har ikke primtalls-teller: %s" % (l+1,Hl1)

Gustav
Tyrann
Tyrann
Posts: 4563
Joined: 12/12-2008 12:44

Ja, kan tenke meg at det tar litt tid.

Tips: Du kan korte ned kjøretiden med å bruke følgende teorem:

http://mathworld.wolfram.com/WolstenholmesTheorem.html

edit: Python-løsningen min tar for øvrig 200 sek. på en middels kjapp laptop
Post Reply