Zeilen und Spaltenweise einlesen und als Bruch darstellen(Zweidimensionales Array)


#1
Hallo zusammen,
ich stehe erneut vor einem Problem. Undzwar soll ich ein Spiel Namens Domino erstellen, der die Felder des Arrays mit den gleichen Augenzahlen aneinander legen und als Bruch darstellen soll.
Zuerst wollte ich mal das einlesen thematisieren. Dies soll über eine zusätzliche Funktion Namens "einlesen" passieren.

Das Problem hierbei ist, dass nach 7 Zeilen Iteration, ich immer noch etwas eingeben kann obwohl ja nach 7 Zeilen die Schleife aufhören soll.
Vielleicht kann mir jemand dabei helfen auch die Ausgabe als Bruch vorerst darzustellen, ohne die Sortierung.

C:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int Steine[7][2];
int i_zeile, i_spalte, k;
    
main(){
    printf("Bitte geben Sie nun 7 Dominosteine ein\n");
    einlesen();
    for(k = 0; k < 7; k++)printf("%d. %d\n", (k+1) ,Steine[k][k]); /*Hier soll die Ausgabe als Bruch dargestellt werden*/
}

einlesen(){
    /*Einlesen der Zahlen, Zeilen- und Spaltenweise*/
    for(i_zeile = 0; i_zeile < 7; i_zeile){
        for(i_spalte = 0; i_spalte < 2; i_spalte){
            scanf("%d", &Steine[i_zeile][i_spalte]);
        }
    }
    
}
 

cwriter

Erfahrenes Mitglied
#2
Das Problem hierbei ist, dass nach 7 Zeilen Iteration, ich immer noch etwas eingeben kann obwohl ja nach 7 Zeilen die Schleife aufhören soll.
Was sollte im letzten Feld eines for-Loops stehen?
for(Start; Condition; Statement). Du hast im Statement eine reine Expression (keine Veränderung des Zustands).


Vielleicht kann mir jemand dabei helfen auch die Ausgabe als Bruch vorerst darzustellen, ohne die Sortierung.
Ehrlich gesagt kann ich mir darunter nichts vorstellen.
Meinst du
Code:
Zahl1 / Zahl2

oder

Zahl1 | Zahl2

oder

Zahl1
---------
Zahl2
cwriter
 
#3
Was sollte im letzten Feld eines for-Loops stehen?
for(Start; Condition; Statement). Du hast im Statement eine reine Expression (keine Veränderung des Zustands).



Ehrlich gesagt kann ich mir darunter nichts vorstellen.
Meinst du
Code:
Zahl1 / Zahl2

oder

Zahl1 | Zahl2

oder

Zahl1
---------
Zahl2
cwriter
Genau Zahl1 / Zahl2 soll ausgegeben werden.
Nur wie mache ich das so, dass es mit einem zweidimensionalen Array funktioniert.
Zuerst natürlich, sollte die Eingabe erfolgen.
:)
 

Technipion

Erfahrenes Mitglied
#4
Ehrlichgesagt sehe ich noch einige andere Problemchen im Code.
Deine main() und die Funktion einlesen() scheinen keinen Typ zu haben?

Außerdem ein kleiner Tipp direkt am Anfang: Die Variablen Steine[][] und i_zeile, i_spalte und k sind sogenannte globale Variablen, weil sie von überall (in deiner Quellcode-Datei) sichtbar sind. Eigentlich versucht man immer so gut es geht globale Variablen zu vermeiden, in seltenen Fällen (oder als Anfänger) kann man sie jedoch benutzen. Allerdings ist es dann immer schön sie als global zu kennzeichnen. Ich z.B. beginne ihre Namen dann immer mit "g_". Also aus int Steine[7][2]; würde dann int g_Steine[7][2];. Nur ein kleiner Tipp, damit erinnert man sich immer daran, dass diese Variablen global sind.

Zur for-Schleife: Hast du verstanden was cwriter gemeint hat? Falls ja poste mal deinen aktualisierten Code. Falls nein: Wo genau liegt das Problem?

Gruß Technipion
 

cwriter

Erfahrenes Mitglied
#5
Zuerst natürlich, sollte die Eingabe erfolgen.
Du inkrementierst die for-loop-Iterationsvariable nicht.
Nur wie mache ich das so, dass es mit einem zweidimensionalen Array funktioniert.
?
C:
printf("%d / %d", Steine[i][0], Steine[i][1]);
Es fällt mir ein bisschen schwer, deinen Kenntnisstand zu lesen. Die logische Herangehensweise bei diesen Dingen geht über die Typen.

Du hast einen Array von einem Array von ints namens Steine. Wir schreiben den Typ mal als [[int]]. Wenn du einmal dereferenzierst, bekommst du den Typ [int]. Das passt aber noch nicht für printf. Also musst du nochmals dereferenzieren. Das tatest du ja schon
Nun ist der 1x dereferenzierte Typ aber int[2]. D.h. du kannst auf 0 und 1 als Index zugreifen.
Vielleicht erklärt das die Herangehensweise ja etwas.

Deine main() und die Funktion einlesen() scheinen keinen Typ zu haben?
Sekiro nutzt C89, wo alles implizit int ist. Nicht mein Stil, aber naja...
Übrigens ist selbst in C11 noch implizit int - da aber mit einer Warnung. Aber anständige Menschen tun das nicht, da hast du schon recht ;)

Eigentlich versucht man immer so gut es geht globale Variablen zu vermeiden, in seltenen Fällen (oder als Anfänger) kann man sie jedoch benutzen. Allerdings ist es dann immer schön sie als global zu kennzeichnen. Ich z.B. beginne ihre Namen dann immer mit "g_". Also aus int Steine[7][2]; würde dann int g_Steine[7][2];. Nur ein kleiner Tipp, damit erinnert man sich immer daran, dass diese Variablen global sind.
Alles völlig richtig, aber für diese Aufgabenprogramme sollte das schon reichen - korrekterweise müsste man es lokal halten und per Pointer übergeben, aber es ist sowieso C89 - und damit ist die Chance, dass dieser Code irgendwo produktiv eingesetzt wird, nahezu 0 ;)

Gruss
cwriter
 
Zuletzt bearbeitet:
#6
Du inkrementierst die for-loop-Iterationsvariable nicht.
?
Jo total übersehen. Vielen Dank.

C:
printf("%d / %d", Steine[i][0], Steine[i][1]);
Es fällt mir ein bisschen schwer, deinen Kenntnisstand zu lesen. Die logische Herangehensweise bei diesen Dingen geht über die Typen.

Du hast einen Array von einem Array von ints namens Steine. Wir schreiben den Typ mal als [[int]]. Wenn du einmal dereferenzierst, bekommst du den Typ [int]. Das passt aber noch nicht für printf. Also musst du nochmals dereferenzieren. Das tatest du ja schon
Nun ist der 1x dereferenzierte Typ aber int[2]. D.h. du kannst auf 0 und 1 als Index zugreifen.
Vielleicht erklärt das die Herangehensweise ja etwas.


Sekiro nutzt C89, wo alles implizit int ist. Nicht mein Stil, aber naja...
Übrigens ist selbst in C11 noch implizit int - da aber mit einer Warnung. Aber anständige Menschen tun das nicht, da hast du schon recht ;)


Alles völlig richtig, aber für diese Aufgabenprogramme sollte das schon reichen - korrekterweise müsste man es lokal halten und per Pointer übergeben, aber es ist sowieso C89 - und damit ist die Chance, dass dieser Code irgendwo produktiv eingesetzt wird, nahezu 0 ;)

Gruss
cwriter[/QUOTE]
Mir ist schon bewusst das man eher zu lokalen Variablen neigt als zu globalen und diese dann an die jeweiligen Funktionen, die man verwenden möchte weitergibt. Die Aufgabe ist es vom Dozenten das Verständnis hinter globalen und lokalen Variablen klar zu machen. Nachher kommt noch eine weitere Funktion, der man dann Laufvariablen i und j übergeben soll. Diese Funktion soll berechnen heißen und die Zahlen der Dominosteine die gleich sind aneinander legen/sortieren.
Beispielsweise:
1. 5/2
2. 6/3
3. 1/4
4. 6/2
unsortiert

1. 5/2
2. 2/6
3. 6/3
4. 1/4
sortiert

Also 2 an 2 und 6 an 6
Dabei kann der Stein auch gedreht werden.
 
Zuletzt bearbeitet:
#7
?
Jo total übersehen. Vielen Dank.

C:
printf("%d / %d", Steine[i][0], Steine[i][1]);
Es fällt mir ein bisschen schwer, deinen Kenntnisstand zu lesen. Die logische Herangehensweise bei diesen Dingen geht über die Typen.

Du hast einen Array von einem Array von ints namens Steine. Wir schreiben den Typ mal als [[int]]. Wenn du einmal dereferenzierst, bekommst du den Typ [int]. Das passt aber noch nicht für printf. Also musst du nochmals dereferenzieren. Das tatest du ja schon
Nun ist der 1x dereferenzierte Typ aber int[2]. D.h. du kannst auf 0 und 1 als Index zugreifen.
Vielleicht erklärt das die Herangehensweise ja etwas.


Sekiro nutzt C89, wo alles implizit int ist. Nicht mein Stil, aber naja...
Übrigens ist selbst in C11 noch implizit int - da aber mit einer Warnung. Aber anständige Menschen tun das nicht, da hast du schon recht ;)


Alles völlig richtig, aber für diese Aufgabenprogramme sollte das schon reichen - korrekterweise müsste man es lokal halten und per Pointer übergeben, aber es ist sowieso C89 - und damit ist die Chance, dass dieser Code irgendwo produktiv eingesetzt wird, nahezu 0 ;)

Gruss
cwriter
Mir ist schon bewusst das man eher zu lokalen Variablen neigt als zu globalen und diese dann an die jeweiligen Funktionen, die man verwenden möchte weitergibt. Die Aufgabe ist es vom Dozenten das Verständnis hinter globalen und lokalen Variablen klar zu machen. Nachher kommt noch eine weitere Funktion, der man dann Laufvariablen i und j übergeben soll. Diese Funktion soll berechnen heißen und die Zahlen der Dominosteine die gleich sind aneinander legen/sortieren.
Beispielsweise:
1. 5/2
2. 6/3
3. 1/4
4. 6/2
unsortiert

1. 5/2
2. 2/6
3. 6/3
4. 1/4
sortiert

Also 2 an 2 und 6 an 6
Dabei kann der Stein auch gedreht werden.[/QUOTE]

Ich benutze momentan den Code Blocks Editor. Wenn ich den Code compilieren möchte, [\QUOTE]
Kann ich keine zweite Eingabe machen. Wieso ? mit Cygwin hatte es irgendwie geklappt.
Der Code sieht bis hierhin wie folgt aus:
C:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int Steine[7][2];
int i_zeile, i_spalte, j, k;

main(){
    printf("Bitte geben Sie nun 7 Dominosteine ein\n");
    einlesen();
    for(k = 0; k < 7; k++)printf("%d. %d/%d\n", (k+1) ,Steine[k][0], Steine[k][1]);
}

einlesen(){
    for(i_zeile = 0; i_zeile < 7; i_zeile++){
        for(i_spalte = 0; i_spalte < 2; i_spalte++){
            scanf("%d. %d", i_zeile, &Steine[i_zeile][i_spalte]);
        }
    }
}
[\CODE]
 
Zuletzt bearbeitet:

cwriter

Erfahrenes Mitglied
#8
Ich benutze momentan den Code Blocks Editor. Wenn ich den Code compilieren möchte,
Kann ich keine zweite Eingabe machen. Wieso ? mit Cygwin hatte es irgendwie geklappt.
Der Code sieht bis hierhin wie folgt aus:
Naja, was macht denn scanf?
Wenn du "%d. %d" als scanf format string hast, dann wird nach i_zeile gelesen - bzw. auch nicht, das Programm sollte abstürzen.
Nimm das "%d." und die 'i_zeile' auis dem Scanf raus, dann solltest du alle Zahlen eingeben können.

Gruss
cwriter
 
#9
Habs denke ich mal verstanden.
Jetzt soll ich noch das mit dem berechnen machen. Ich hab da mal was geschrieben, jedoch blicke ich da noch nicht richtig durch, wie ich das realisieren soll, dass der überübernächste kontrolliert werden soll. Das ganze soll rekursiv erfolgen. Also das sich die Funktion berechnen selbst aufruft.
Ich dachte da an eine geschachtelte for in for Schleife aber dann ist es doch nicht mehr rekursiv oder ?
C:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int Steine[7][2];
int berechnen(int, int);
int i, j;
int main(){


    printf("Bitte geben Sie nun 7 Dominosteine ein\n");
    einlesen();
    for(i = 0; i < 7; i++)printf("%d. %d/%d\n", (i+1) ,Steine[i][0], Steine[i][1]);
    i = 0; j = 0;
    berechnen(i,j);
    return 0;
}

void einlesen(){
    for(i = 0; i < 7; i++){
        printf("%d.\n", (i+1));
        for(j = 0; j < 2; j++)
          scanf("%d", &Steine[i][j]);
    }
}

/*Überprüfung, ob der aktuelle Stein durch Anlegen mit dem nächsten Stein identisch ist bsp: 1.)3/4,4/2,2/1*/
/*Auch durch drehen*/
int berechnen(int i, int j) {
    int temp1, temp2;
    if(Steine[i][0] == Steine[j][0])
    {
        i++;
        j++;
        brechnen(i,j);
    }
    else
        if(Steine[i][0] == Steine[j][1])
        {
            temp1 = Steine[j][0];
            temp2 = Steine[j][1];
            Steine[j][0] = temp2;
            Steine[j][1] = temp1;
        }
    else{
        /*Wenn der aktuelle Stein nicht passt soll der übernächste Stein überprüft werden. Wenn dieser nicht passt
        soll der überübernächste Stein überprüft werden*/
    }

}
 

cwriter

Erfahrenes Mitglied
#10
Jetzt soll ich noch das mit dem berechnen machen. Ich hab da mal was geschrieben, jedoch blicke ich da noch nicht richtig durch, wie ich das realisieren soll, dass der überübernächste kontrolliert werden soll.
Da sind wir ja schon zwei.


Ich dachte da an eine geschachtelte for in for Schleife aber dann ist es doch nicht mehr rekursiv oder ?
Naja - auch mit 2 Schleifen kann sich eine Funktion noch selbst aufrufen...


Da ich dir nicht die Arbeit abnehmen will, aber dennoch einen guten Rat geben kann, habe ich mal ein Beispiel in C++ implementiert. Das ist ähnlich genug, um den Algorithmus zu zeigen, aber weit genug entfernt, dass man nicht mit "1 zu 1" umschreiben davonkommt. Am besten lässt du das Beispiel durch einen C++ Compiler, um die Resultate zu sehen:
C++:
#include <iostream>
#include <time.h>
#include <vector>
#include <string>

constexpr size_t blockcount = 10;

struct Stein {
    Stein(int a, int b)
        : v1(a), v2(b) {

    }

    std::string format(bool normal = true) const {
        auto a = normal ? v1 : v2;
        auto b = normal ? v2 : v1;
        return "(" + std::to_string(a) + "|" + std::to_string(b) + ")";
    }

    std::string format(int expect) const {
        return format(expect == v1);
    }
    int v1;
    int v2;
};

std::vector<int> berechne(std::vector<int> used, const std::vector<Stein>& all, int i, int orientation)
{
    // Copy the existing path as a reference return value
    decltype(used) maxpath = used;

    // Check all bricks
    for (size_t j = 0; j < all.size(); ++j)
    {
        // Check if the current brick being checked is not already used
        bool not_this = false;
        for (size_t f = 0; f < used.size(); ++f) {
            if (used[f] == j) {
                not_this = true;
                continue;
            }
        }

        if (not_this) continue; // Skip if already used

        // Copy the orientation
        decltype(orientation) new_orientation = orientation;
        // If not the first block
        if (i != -1)
        {
            // Set the orientations of the next blocks
            if (orientation == 1 || orientation == 0) {
                // "Normal"
                if (all[i].v2 == all[j].v1) {
                    // orientation stays the same
                    new_orientation = 1;
                }
                else if (all[i].v2 == all[j].v2) {
                    // swap
                    new_orientation = -1;
                }
                else continue;
            }
            else if (orientation == -1 || orientation == 0) {
                // Inverted
                if (all[i].v1 == all[j].v1) {
                    // swap
                    new_orientation = 1;
                }
                else if (all[i].v1 == all[j].v2) {
                    // still -1
                    new_orientation = -1;
                }
                else continue;
            }
            else {
                // No match in any orientation, continue
                continue;
            }
        }
        // Copy the current state
        auto cpy = used;
        // Add the selected value to the copied state
        cpy.push_back(j); // Add to list
        // Recurse
        auto r = berechne(cpy, all, j, new_orientation);
        // Assign the maxpath if the path was deeper (As this is DFS)
        if (maxpath.size() < r.size())
            maxpath = r;
    }

    // Return the found path
    return maxpath;

}

int main(int argc, char* argv[])
{
    // Randomize and fill
    srand(time(NULL));

    auto rf = []() { return (rand() % 10) + 1; };

    std::vector<Stein> steine;

    for (size_t i = 0; i < blockcount; ++i) {
        steine.push_back(Stein(rf(), rf()));
    }

    // Start by setting any start block (-1) and a fixed orientation
    std::vector<int> used;
    auto ret = berechne(used, steine, -1, 1);

    // Dump info for all bricks
    std::cout << "All bricks: " << std::endl;
    for (const auto& x : steine) {
        std::cout << x.format() << " => ";
    }

    // Dump info about the sorting
    std::cout << std::endl << "Sorted bricks: " << std::endl;
    int lastval = -1;
    for (const auto& x : ret) {
        if (lastval == -1) {
            // We know that we started with orientation = 1
            lastval = steine[x].v2;

            std::cout << steine[x].format(true) << " => ";
        }
        else {
            std::cout << steine[x].format(lastval) << " => ";
            lastval = steine[x].v1 == lastval ? steine[x].v2 : steine[x].v1;
        }
    }
    std::cout << "\n (missing " << steine.size() - ret.size() << " brick(s))" << std::endl;

    return 0;
}
Kurze Theorie dazu: Das ist ein DFS (depth first search) basierter Ansatz, der sehr teuer ist, was Stack / Speicher angeht, aber einfach zu verstehen.
Im Prinzip wird in jeder Tiefe geschaut, welche Steine passen. Für jeden der passenden Steine wird das Problem verkleinert (minus den Stein, der gerade genommen wurde) und wieder gelöst.

Ich habe keine Ahnung, wie es mit nur den 2 Parametern i und j gehen soll, und es macht auch keinen Sinn, Rekursion und Iteration (mit Speicher ausserhalb) zu mischen.

Dieser Code findet immer einen Optimalen Pfad. Als Übung kannst du den Beweis dazu schreiben :)
Vielleicht hilft das ja als Ansatz.

Tipps für C++ => C:
1) push_back fügt ein Element ans Ende des Arrays an. In C macht man das normalerweise, indem man einen genügend grossen Array reserviert und eine Iterationsvariable hat, an deren Position eingefügt wird, und dann wird diese Variable um 1 erhöht. Es gibt hier aber auch elegantere Methoden (da ohnehin kopiert wird) mit memcpy.
2) decltype übernimmt den Typ einer Variable.
3) auto übernimmt den Typ der zugewiesenen Variable
4) In diesem Beispiel werden die Vektoren by value übergeben. C-Arrays müssen zuerst kopiert werden!
5) std::cout kann man mit printf() ersetzen, std::string mit const char*. Aber: Scopes im Auge behalten! (Compilerwarnungen lesen, -Wall -Wextra)
6) Stein ist ein Struct mit einem Konstruktor. Die Memberfunktionen kannst du ebenfalls schnell umschreiben.

Gruss
cwriter
 
#11
Mit dem C++ Code konnte ich leider nichts anfangen. Ich schicke ma trotzdem die Aufgabenstellung.

Die Funktion berechnen(int i, int j) soll folgendes machen.
  • mit dem aktuellen Stein i soll immer der Nachfolger j im Array Steine betrachtet werden.
  • Passt der aktuelle Nachfolger wird die Funktion verlassen und der nächste Stein betrachtet.
  • Passt der aktuelle Nachfolger indem man ihn dreht, dann wird er gedreht, die Funktion wird verlassen und der nächste Stein betrachtet.
  • Passt der aktuelle Nachfolger nicht(auch nicht durch drehen), dann wird die Funktion berechnen(int i, int j) erneut aufgerufen(Rekursion) und der übernächste Nachfolger überprüft. Passt der übernächste nicht, wird der überübernächste überprüft usw..
  • D.h. wenn Sie im Hauptprogramm Stein i = 1 an berechnen(int i, int j) übergeben haben, dann überprüft berechnen(int i, int j) rekursiv der Reihe nach die Steine j = 2 ... 7, ob sie (ggf. auch durch drehen) passen. Wenn Sie im Hauptprogramm Stein j = 4 an berechnen(int i, int j) übergeben haben, dann überprüft berechnen(int i, int j) rekursiv der Reihe nach die Steine 5 - 7, ob sie (ggf. auch durch drehen) passen
  • Falls der übernächste, drittnächste etc. Stein passt, wird er mit dem unmittelbar nächsten Stein im Array Steine vertauscht.
  • Wenn es bei den restlichen Steinen keinen passenden Anlegekandidaten mehr gibt soll das Spiel mit einer entsprechenden Bildschirmausgabe beendet werden.
D.h bei jedem Drehen oder Steinetausch, wird die Reihenfolge bzw. Anordnung der Steine Array Steine aktualisiert.

Idee:
Zuerst dachte ich daran, dass ich in der main eine For-Schleife schreibe und die Laufvariable i übergebe aber da bin ich mir nicht sicher ob ich da richtig liege, da ich ja auch irgendwie die Variable j übergeben muss. Also meine Frage hier muss ich in der main eine for in for schreiben mit den jeweiligen Variablen i für die äussere Schleife und j für die innere Schleife ?
Wenn ja, wie mache ich das mit der Rekursion in der Funktion berechnen(int i, int j) ?
 

Technipion

Erfahrenes Mitglied
#12
Also meine Frage hier muss ich in der main eine for in for schreiben mit den jeweiligen Variablen i für die äussere Schleife und j für die innere Schleife ?
Jein. So wie ich das sehe brauchst du in der main() zwar eine for-Schleife, die über i = 0 .. n läuft, aber das j soll eigentlich von der Funktion berechnen(i, j) selbst bestimmt werden (über Rekursion). Also quasi
Code:
main {
    for i in 0 .. n {
        ...
        berechnen(i, i+1);
        ...
    }
}


func berechnen(i, j) {
    // teste ob Stein Nr. j passt:
    ...
    // ggf. nächsten Stein überprüfen:
    berechnen(i, j+1); // <--- Rekursion
}
Gruß Technipion
 

cwriter

Erfahrenes Mitglied
#13
Zuerst dachte ich daran, dass ich in der main eine For-Schleife schreibe und die Laufvariable i übergebe aber da bin ich mir nicht sicher ob ich da richtig liege, da ich ja auch irgendwie die Variable j übergeben muss.
Das ist nicht allzu falsch.

Wenn ja, wie mache ich das mit der Rekursion in der Funktion berechnen(int i, int j) ?
Gehen wir doch mal die Aufgabenstellung durch:
mit dem aktuellen Stein i soll immer der Nachfolger j im Array Steine betrachtet werden.
Interessiert nicht, ist nur Overview.
Passt der aktuelle Nachfolger wird die Funktion verlassen und der nächste Stein betrachtet.
Da haben wir:
C:
int berechnen(int i, int j)
{
    if(passt(i, j)) return:
}
Passt der aktuelle Nachfolger indem man ihn dreht, dann wird er gedreht, die Funktion wird verlassen und der nächste Stein betrachtet.
Daraus folgt:
C:
int berechnen(int i, int j)
{
    if(passt(i, j)) return 0:
    if(passt(i, gedreht(j)))
    {
        drehe(j);
        return 0;
    }
}
Passt der aktuelle Nachfolger nicht(auch nicht durch drehen), dann wird die Funktion berechnen(int i, int j) erneut aufgerufen(Rekursion) und der übernächste Nachfolger überprüft. Passt der übernächste nicht, wird der überübernächste überprüft usw..
Also:
C:
int berechnen(int i, int j)
{
    if(passt(i, j)) return 1:
    else if(passt(i, gedreht(j)))
    {
        drehe(j);
        return 1;
    }
    else
    {
        berechnen(i, j+1);
    }
}
Falls der übernächste, drittnächste etc. Stein passt, wird er mit dem unmittelbar nächsten Stein im Array Steine vertauscht.
Also:
C:
int berechnen(int i, int j)
{
    if(passt(i, j)) return 1:
    else if(passt(i, gedreht(j)))
    {
        drehe(j);
        return 1;
    }
    else
    {
        if(berechnen(i, j+1) == 1)
        {
            tausche(i+1, j+1);
        }
    }
}
Als nächstes ist die Aufgabenstellung mehr als schlecht (mehr dazu später), aber man kann sich ja selbst was überlegen:
C:
int berechnen(int i, int j)
{
    if(i > max_stein || j > max_stein) return 0; // Bounds check
    if(passt(i, j)) return 1:
    else if(passt(i, gedreht(j)))
    {
        drehe(j);
        return 1;
    }
    else
    {
        if(berechnen(i, j+1) == 1)
        {
            tausche(i+1, j+1);
        }
    }
    return 0; // Muss was zurückgeben
}
Ok, dann zur main: Aus der Aufgabenstellung ist das nicht ganz klar, aber da i nicht verändert wird, muss das wohl mit einer Schleife in der main geschehen:
C:
for(i...)
{
    if(berechnen(i, i+1) == 0) // Warum i, i+1? => Weil j per Definitionem ein Nachfolger sein muss
    {
        // Ende der Fahnenstange
    }
}
So, viel zu viel geholfen. Nun zum Rant:

Die Aufgabenstellung ist falsch bzw. löst das implizierte Problem nicht. Genauer gesagt ist das ein Greedy-Algorithmus (nimmt die erstbeste Möglichkeit). Das führt zu suboptimalen Resultaten. Ein Beispiel gefällig?
Code:
(1 | 2) => (2 | 3) => (2 | 2) => (3 | 4) => (4 | 5) => ... usw (in die Unendlichkeit)
Es ist offensichtlich, dass hier eine unendlich lange Kette möglich wäre, die alle Steine benutzt (Stein 1, Stein 3, Stein 2, Stein 4, Stein 5, ....). Aber der Beschriebene Algorithmus wird immer den Stein (2 | 2) übrig haben. Warum? Weil er den Stein (2 | 3) nimmt und der Stein (2 | 2) niemals mehr passen wird.
Ok, also haben wir herausgefunden, dass der Algorithmus nicht maximiert. (Dieses Beispiel ist ein einfacher Fall, um zu beweisen, dass der Algorithmus inkorrekt ist - es gibt viele andere Probleme durch die Erzwungene Startorientierung ohne Option, einen anderen Startpunkt zu wählen und die inkomplette Aufzählung der Möglichkeiten).
Dann ist die Rekursion hier völliger Blödsinn und hat überhaupt keine Existenzberechtigung. Man nutzt den Stack ja nicht einmal für Zwischenwerte. (= Unnötiger Stackoverflow für nichts und wieder nichts).
Rekursion ist dann einfacher als Iteration, wenn man einen Zustandsautomaten mit Variablen bauen will. Hier wird das weggeworfen.

Ok, dann schauen wir uns mal die Laufzeit an. Die Laufzeit hier ist O(n^2) durch die beiden Iteratoren. Ist das besser als mein Code oben?
Mein Code hat eine Laufzeit von O(n^n), also ja: Hier ist der Algorithmus der Aufgabe besser.
Parallelisierbarkeit: Nicht vorhanden im Aufgabenalgorithmus, vorhanden im Vorschlag.


Ach, der Professor wollte wohl nett sein und ein abwechslungsreiches Beispiel bringen, aber ich sehe nichts gutes an der Aufgabe.
Naja, mit den Tipps ist die Aufgabe ja immerhin lösbar.

Gruss
cwriter
 
#14
Ich habe das jetzt mal wie folgt geschrieben, jedoch wird mir vom compiler gesagt, dass es 2 Fehler gibt.

C:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int Steine[7][2];
int berechnen(int, int);
int i, j, temp;
int main(){


    printf("Bitte geben Sie nun 7 Dominosteine ein\n");
    einlesen();
    for(i = 0; i < 7; i++)printf("%d. %d/%d\n", (i+1) ,Steine[i][0], Steine[i][1]);
    for(i = 0; i < 7; i++)
      if(berechnen(i, i+1) == 0)
        {

        }
    return 0;
}

void einlesen(){
    for(i = 0; i < 7; i++){
        printf("%d.\n", (i+1));
        for(j = 0; j < 2; j++)
          scanf("%d", &Steine[i][j]);
    }
}

int berechnen(int i, int j) {
    if(i > 7 || j > 7) return 0;
    if(Steine[i][0] == Steine[j][0])
        return 1;
    else
        if(Steine[i][0] == Steine[j][1])
        {
            /*Drehen*/
            temp = Steine[j][1];
            Steine[j][1] = Steine[j][0];
            Steine[j][0] = temp;
            return 1;
        }
    else{
            brechnen(i, (j+1));
        }
    return 0;
}
 

Technipion

Erfahrenes Mitglied
#15
jedoch wird mir vom compiler gesagt, dass es 2 Fehler gibt.
Ich weiß das klingt jetzt weit hergeholt, aber wie wäre es - für die Zukunft - wenn du diese Fehler dann auch mitposten würdest?

Mir fällt direkt auf, dass in der main() die Funktion einlesen() benutzt wird, die der Compiler aber zu dem Zeitpunkt noch gar nicht kennt. Das müsste also einen Error erzeugen. Lösung? Lege ganz oben einen Prototypen an, genau wie bei berechnen(...).

Ich halte mich aber zunächst noch zurück, ich kann nämlich schon cwriters Tastatur klackern hören :LOL:
 

cwriter

Erfahrenes Mitglied
#18
Es wird auch nicht wirklich getauscht.
Nummer 42 der Sekiro'schen Weisheiten. :rolleyes:

Du hast in deinem Code auch keine Zeile, die das tun sollte...

Nicht böse gemeint, aber du solltest wirklich deine Arbeitsweise überdenken. Du eröffnest ein Thema (vor einem Monat), dann liegt es ein paar Wochen brach ohne Lebenszeichen und dann bekommen wir vorwurfsvolle Einzeiler vorgelegt.
Wir sind geduldig und haben schon viel gesehen (und wollen dich sicher nicht entmutigen), aber erweise uns doch den Respekt, etwas mehr Gedanken in deine Posts einfliessen zu lassen. Wenn du etwas nicht verstehst, dann frage nach einer Erklärung (idealerweise mit einer Beschreibung, warum du etwas nicht verstehst). Wenn etwas nicht kompiliert, dann gib uns die Fehlermeldungen (idealerweise 1 zu 1 kopiert). Wenn der Code etwas nicht tut, was er deiner Meinung nach tun sollte, dann sage uns, warum du meinst, dass die Funktionalität da sein soll und wo du die betreffenden Codezeilen vermutest.

Wir geben uns Mühe, unsere Posts so hilfreich wie möglich zu schreiben und lassen viele Gedanken einfliessen - entsprechend kann es sein, dass man mal 20-30 Minuten über einem Post sitzt. Entgegne diese Höflichkeit, indem du es uns gleichtust.

Ok, Schwamm drüber, Blick nach vorne: Zu deinem Problem.

Jetzt, da du weisst, dass du den Code nicht hast: Wo ist der Knoten, der dich daran hindert, den Code zu schreiben?

Gruss
cwriter
 
#19
Sorry nochmal trotzdem, musste in letzter Zeit mehr für andere Fächer machen.
Also ich habe eben bemerkt das ich das mit dem tauschen offensichtlich nicht habe - eingesehen.
Du hast dazu folgendes geschrieben:

if(berechnen(i, j+1) == 1) { tausche(i+1, j+1); }
Für die Stelle wo getauscht werden soll, also "tausche(i+1 , j+1)", habe ich folgendes geschrieben:

C:
if (berechnen(i, j+1) == 1)
                {
                  /*Tauschen*/
                  temp = Steine[i + 1][0];
                  temp1 = Steine[i + 1][1];
                  Steine[i + 1][0] = Steine[j + 1][0];
                  Steine[i + 1][1] = Steine[j + 1][1];
                  Steine[j + 1][0] = temp;
                  Steine[j + 1][1] = temp1;
                }
 

cwriter

Erfahrenes Mitglied
#20
Sorry nochmal trotzdem, musste in letzter Zeit mehr für andere Fächer machen.
Das kann ich durchaus verstehen :). Allerdings ist meine Erfahrung, dass man solche Programme jeweils in höchstens einer Woche bearbeiten sollte, da man sonst mehr Zeit mit dem Wieder-Einlesen verbringt als mit dem Problem selbst. Aber vielleicht ist das bei dir ja anders. Und es kann ja immer etwas wichtigeres dazwischenkommen, da hast du schon recht.

Für die Stelle wo getauscht werden soll, also "tausche(i+1 , j+1)", habe ich folgendes geschrieben:
Ok, damit sieht das Programm eigentlich schon recht komplett aus. Ich habe das Programm selbst nicht geschrieben/nicht ausgeführt; geht es denn jetzt wie erwartet?

Gruss
cwriter