Klassischer Algorithmus ----- Josephs Problem (C-Sprache)

 Inhaltsverzeichnis

Vorwort

Hintergrund der Geschichte

Joseph-Problem

Zirkuläre verknüpfte Listenlösung

 Array-Lösung


Vorwort

        Heute spielen wir ein interessantes Problem, nämlich das Joseph-Problem. Dieses Problem stammt aus einer Geschichte aus dem europäischen Mittelalter. Jetzt werden wir dieses interessante Problem durch Programmierung lösen. Werfen wir einen Blick darauf!

Hintergrund der Geschichte

        Es heißt, dass der berühmte jüdische Historiker Josephus die folgende Geschichte hatte: Nachdem die Römer Chotapat erobert hatten, versteckten sich 39 Juden mit Josephus und seinen Freunden in einer Höhle. Die 39 Juden beschlossen, dass sie lieber sterben würden, als vom Feind gefangen zu werden. , so Es wurde eine Selbstmordmethode beschlossen. 41 Personen stellten sich im Kreis auf und die erste Person begann zu zählen. Jedes Mal, wenn die dritte Person gezählt wurde, musste diese Person Selbstmord begehen, und dann zählte die nächste Person erneut, bis alle Selbstmord begingen. Bis zum Tod. Josephus und seine Freunde wollten jedoch nicht nachkommen. Beginnen Sie zunächst mit einer Person, kreuzen Sie k-2 Personen (da die erste Person gekreuzt wurde) und töten Sie die k -te Person. Gehen Sie dann an k-1 Personen vorbei und töten Sie die k -te Person. Dieser Prozess setzt sich im Kreis fort, bis schließlich nur noch eine Person übrig bleibt und diese Person weiterleben kann. Die Frage ist, wo man zunächst stehen sollte, um einer Hinrichtung zu entgehen. Josephus bat seinen Freund, zuerst so zu tun, als würde er gehorchen. Er platzierte seinen Freund und sich selbst auf der 16. und 31. Position und entging so dem Todesspiel.

        Der französische Mathematiker Gaspar aus dem 17. Jahrhundert erzählte in „Das Spiel der Zahlen“ eine solche Geschichte: 15 Gläubige und 15 Ungläubige befanden sich in der Tiefsee in Gefahr. Die Hälfte von ihnen musste ins Meer geworfen werden, bevor der Rest überleben konnte. Es war schwierig, also habe ich mir einen Weg ausgedacht: 30 Leute versammelten sich im Kreis, gezählt von der ersten Person, und jede neunte Person wurde ins Meer geworfen. Dieser Zyklus ging weiter, bis nur noch 15 Leute übrig waren. Ich frage, wie man es so gestalten kann, dass jedes Mal, wenn diejenigen, die ins Meer geworfen werden, Ungläubige sind.

Joseph-Problem

Holen Sie sich zwei Daten von der Tastatur, n und s. n stellt die Anzahl der Personen dar und s stellt die Zählung ab der ersten Person dar. Wenn die s. Person gezählt ist, scheidet diese Person aus. Frage: Wer ist die letzte Person, die noch übrig ist? mehrere ?

Zirkuläre verknüpfte Listenlösung

        Hier können wir dieses Problem in Form einer kreisförmig verknüpften Liste lösen. Das Prozessdiagramm lautet wie folgt:

Erstellen Sie zunächst eine entsprechende kreisförmig verkettete Liste basierend auf der aktuell eingegebenen Personenzahl und speichern Sie darin nacheinander den Standort jeder Person.

 Beginnen Sie dann mit der Zählung ab der ersten Person und führen Sie den Löschvorgang aus, wenn die dritte Person gezählt wird, wie unten gezeigt, und starten Sie dann eine neue Runde ab dem vierten Knoten ...

Der Code sieht so aus: 

#include <stdio.h>
#include<stdlib.h>
//节点
typedef struct node {
	int num;
	struct node* next;
}Node;

//创建一个环形链表
Node* create_list(int n) {
	Node* head, * tail;
	head = tail = NULL;
	for (int i = 0; i < n; i++) {
		Node* p = (Node*)malloc(sizeof(Node));
		p->num = i + 1;    //依次标记当前位置
		if (head == NULL) {
			head = p;
			tail = p;
			head->next = NULL;
		}
		else
		{
			tail->next = p;
			tail = p;
		}
		tail->next = head;
	}
	return head;  //返回头结点
}

int main() {
	int n, s;
	printf("请输入:");
	scanf("%d %d", &n, &s);
	Node* cur = create_list(n);
	int count = 1; //此时cur指向的是第一个节点,所以count为1
	while (n != 1) {	//当n=1时候,结束循环,此时剩下最后一个人
		count++;//先进行count统计
		if (count == s) {
			n--;	
			//进行删除节点操作
			Node* del_node = cur->next;	
			cur->next = del_node->next;
			free(del_node);//释放掉这个节点
			//此时count回归到1,也就是重新开始新的一轮
			count = 1;
		}
		cur = cur->next;
	}
	printf("最后剩下的是:%d\n", cur->num);
}

 Array-Lösung

         Im Gegensatz zur verknüpften Liste kann das Array die Anzahl der Personen nicht anpassen, was bedeutet, dass die Anzahl des Arrays hier im Voraus geschrieben wird und die Ausführungseffizienz des Arrays höher ist. Die zirkuläre verknüpfte Liste muss durch Durchlaufen ausgeführt werden. Das hat eine höhere zeitliche Komplexität. ist O(n), und das Array kann diese Position mit einer zeitlichen Komplexität von O(1) direkt finden. Es ist nicht erforderlich, sie einzeln zu durchlaufen. Der Code lautet wie folgt:

//数组实现
#include<stdio.h>
void function(int* num, int length, int s, int start) {
	int count = 0;
	int i = start - 1;//标记起始位置
	int n = length;	//当前人数
	while (n != 1) {
		i = (i + s - 1) % n;	//下一个出局人的位置
		for (int j = i + 1; j < length; j++)
			num[j - 1] = num[j];	//进行删除操作,把要删除的数字后面的依次往前移动,覆盖掉这个要删除的数字
		n--;//删除操作完成,减少一个人
		if (i == n) {	//当i超出数组范围的时候,i就回归到第一个为止
			i = 0;
		}
	}
	printf("最后一个 :%d", num[i]);
	return;
}

int main() {
	int num[6];//这里就已经定义好了6个人
	int s;	//每次数到s,出局一个
	printf("请输入:");
	scanf("%d", &s);
	for (int i = 0; i < sizeof(num) / sizeof(int); i++)
		num[i] = i+1;
	function(num, sizeof(num) / sizeof(int), s, 0);
}

Das war’s für heute, bis zum nächsten Mal!

Teilen Sie ein Hintergrundbild:

Supongo que te gusta

Origin blog.csdn.net/m0_73633088/article/details/133031010
Recomendado
Clasificación