C# :: Aufgabe #88 :: Lösung #2

2 Lösungen Lösungen öffentlich
#88

Gesellige Zahlen finden

Fortgeschrittener - C# von eulerscheZhl - 13.02.2015 um 19:56 Uhr
Eine Zahl ist dann vollkommen, wenn sie gleich der Summe ihrer Teiler ist. (Bsp.: die Teiler von 6 sind 1,2,3 und 1+2+3=6)
Es gibt aber auch Zahlenpaare, die jeweils die andere Zahl als Teilersumme besitzen (Bsp.: 220 und 284), befreundete Zahlen.
Dies lässt sich mit den geselligen Zahlen sogar noch steigern: hier ergibt nicht die Teilersumme von zwei Zahlen die jeweils andere, sondern es lässt sich eine Kette aus mehreren Zahlen bilden (Bsp.: 12496, 14288, 15472, 14536, 14264)

Finde alle Gruppen von geselligen Zahlen, bei denen keine eine Obergrenze (z.B. 10^7) übersteigt.
#2
2 Kommentare
1x
vote_ok
von eulerscheZhl (5230 Punkte) - 09.03.2015 um 16:11 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

namespace trainYourProgrammer
{
	class MainClass
	{
		private static int[] CalcSigma(int limit) { //Summe der Teiler für jede Zahl <= limit
			int[] result = new int[limit + 1];
			for (int i = 2; i <= limit; i++) {
				result [i] = 1;
			}
			for (int i = 2; i * 2 <= limit; i++) {
				for (int j = 2 * i; j <= limit; j += i) {
					result [j] += i;
				}
			}
			return result;
		}

		private static List<List<int>> SocialNumbers(int limit) {
			List<List<int>> result = new List<List<int>> ();
			int[] sigma = CalcSigma (limit);
			for (int i = 2; i <= limit; i++) {
				List<int> chain = new List<int> (5);
				int tmp = i;
				while (tmp > 0 && tmp <= limit && !chain.Contains(tmp)) {
					chain.Add (tmp);
					tmp = sigma [tmp];
				}
				if (chain.Count > 2 && tmp == chain [0]) { //mache >2 zu == 2 für befreundete Zahlen bzw. == 1 für vollkommene Zahlen
					result.Add (chain);
				}
				if (tmp == chain [0] || tmp == 0 || tmp > limit) {
					foreach (int j in chain) { //eine Zahl kann nicht in 2 verschiedenen Ketten vorkommen
						sigma [j] = 0;
					}
				}
			}
			return result;
		}

		public static void Main(string[] args) {
			const int limit = (int)1e7;
			Stopwatch sw = Stopwatch.StartNew ();
			List<List<int>> numbers = SocialNumbers (limit);
			foreach (List<int> chain in numbers) {
				Console.WriteLine (String.Join (", ", chain));
			}
			sw.Stop ();
			Console.WriteLine ("\nbenötigte Zeit: " + sw.ElapsedMilliseconds/1000.0 + " s");
		}
	}
}

Kommentare:

Robi

Punkte: 390


10 Lösungen
6 Kommentare

#1
06.01.2016 um 13:56 Uhr
Die zwei for-Schleifen zur Berechnung der Summe der Teiler ist genial! Wie bist du darauf gekommen? Ich hab auch eine Lösung geschrieben, welche aber im Vergleich zu deiner extrem langsam ist..
post_arrow
255 0

eulerscheZhl

Punkte: 5230

110 Aufgaben
76 Lösungen
64 Kommentare

#2
06.01.2016 um 14:06 Uhr
Danke für die Blumen :)
Im Grunde ist das das Sieb des Eratosthenes. Nur dass ich statt eines bool[] Array, mit dem ich nur weiß, ob die Zahl prim ist, die Teilersumme speichere.

Das kann man auch so variieren, dass man den kleinsten Teiler speichert. Auf diese Weise kann man sich dann durch Division (also index = index / kleinsterTeiler[index]) zur 1 durcharbeiten und so eine Primfaktorzerlegung durchführen.
post_arrow
256 0
Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben