Hackerboard Wiki HaboBlog
Hackerboard bei Facebook Hackerboard bei Google+ Hackerboard bei Twitter

[HaBo]

 
Programmieraufgaben Hier wird regelmäßig eine neue Programmieraufgabe gestellt, die dann gelöst werden soll und in Zusammenarbeit mit den Moderatoren auch besprochen werden kann.

Ein Schachbrett - acht Damen

Diskussion: Ein Schachbrett - acht Damen im Forum Programmieraufgaben, in der Kategorie Code Kitchen; Anzeige Eingereicht von JTron, mich wundert es, dass es diesen Klassiker noch nicht gab ;) Das Programm soll dem Benutzer ...

Antwort
Alt 17.12.07, 22:29   #1 (permalink)
CDW
Moderator
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 202
Standard Ein Schachbrett - acht Damen

Anzeige

Eingereicht von JTron,
mich wundert es, dass es diesen Klassiker noch nicht gab ;)


Das Programm soll dem Benutzer alle Möglichkeiten zeigen, wie man 8 Damen auf einem Schachbrett platzieren kann, ohne dass sie sich gegenseitig bedrohen. Am besten so:

0 = leer
1 = dame

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Zur Erinnerung: eine Dame kann eine andere Figur sowohl horizontal, vertikal wie auch diagonal "bedrohen". D.h sie sollten sich nicht in die Quere kommen.
Schöner wäre es natürlich, wenn das Programm das allgemeine Problem löst: n-Damen auf einem nXn Brett

__________________
Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
Selig, wer nichts zu sagen hat und trotzdem schweigt.
CDW ist offline   Mit Zitat antworten
Alt 17.12.07, 22:53   #2 (permalink)
Senior Member
 
Benutzerbild von lookshe
 
Registriert seit: 10.03.07
lookshe Leistung: 8086
Likes: 19
Standard

Ich durfte das im ersten Semester im Informatikunterricht schon lösen in Setl2.

Einfach am Anfang die Anzahl der Damen aendern und man kann beliebiege Feldgrößen berechnen. Ausgabe ist allerdings etwas anders als vorgegeben, hab keine Lust das jetzt noch anzupassen.

Hier mal die Lösung ohne Kommentare:

Code   

Code:
program main;
    numberQueens := 8;
    board := createBoard(numberQueens);
    print(board);
    print("\n");

    Clauses := allClauses(board);
    print("Test: Aufgabe 7");
    print("This should print a formula that is equivalent to the " 
          + numberQueens + "-queens-problem.");
    print(Clauses);
    print("\n");

    if Clauses /= om then
        I := DavisPutnam(Clauses,{});
    end if;

    if I /= FALSE then
        printBoard(I, board);
    else
        print("The problem is not solvable for " + numberQueens + " queens!");
        print("Try to increase the number of queens.");
    end if;

    procedure atMostOne(S);
		return {{["-",p1],["-",p2]} : p1 in S, p2 in S | p1/=p2};
    end atMostOne;

    procedure atMostOneInRow(board, row);
		return atMostOne(board(row));
    end atMostOneInRow;    

    procedure atMostOneInColumn(board, column);
		i:=#board;
		M:={ board(row)(column) : row in [1..i]};
		return atMostOne(M);
    end atMostOneInColumn;

    procedure atMostOneInUpperDiagonal(board, k);
		i:=#board;
		M:={ board(row)(column) : row in [1..i], column in [1..i] | row+column=k};
		return atMostOne(M);
    end atMostOneInUpperDiagonal;

    procedure atMostOneInLowerDiagonal(board, k);
		i:=#board;
		M:={ board(row)(column) : row in [1..i], column in [1..i] | row-column=k};
		return atMostOne(M);
    end atMostOneInLowerDiagonal;

    procedure oneInRow(board, row);
		return {{x : x in board(row)}};
    end oneInRow;

    procedure allClauses(board);
		i:=#board;
		M1:={atMostOneInRow(board,row) : row in [1..i]};
		M2:={atMostOneInColumn(board,column) : column in [1..i]};
		M3:={atMostOneInUpperDiagonal(board,k) : k in [2..16]};
		M4:={atMostOneInLowerDiagonal(board,k) : k in [-7..7]};
		M5:={oneInRow(board,row) : row in [1..i]};
		Klausel:=+/M1 + +/M2 + +/M3 + +/M4 + +/M5;
		return Klausel;
    end allClauses;

    procedure createBoard(n);
        return [ createRow(n, i) : i in [1..n] ];
    end createBoard;

    procedure createRow(n, i);
        return [ "p" + i + j : j in [1..n] ];
    end createRow;

    procedure printBoard(I, board);
        if I = om then
            return;
        end if;
        n := #board;
        print( "        " + ((8*n+1) * "-") );
        for row in [1..n] loop
            line := "        |";
            for col in [1..n] loop
                line +:= "       |";
            end loop;
            print(line);
            line := "        |";
            for col in [1..n] loop
                if { board(row)(col) } in I then
                    line +:= "   Q   |";
                else
                    line +:= "       |";
                end if;
            end loop;
            print(line);
            line := "        |";
            for col in [1..n] loop
                line +:= "       |";
            end loop;
            print(line);
            print( "        " + ((8*n+1) * "-") );
        end loop;
    end printBoard;

    procedure printBoardSmall(I, board);
        n := #board;
        print( "        " + ((2*n+1) * "-") );
        for row in [1..n] loop
            line := "        |";
            for col in [1..n] loop
                if { board(row)(col) } in I then
                    line +:= "Q|";
                else
                    line +:= " |";
                end if;
            end loop;
            print(line);
            print( "        " + ((2*n+1) * "-") );
        end loop;
    end printBoardSmall;

    procedure DavisPutnam( Clauses, Literals );
        Clauses := saturate(Clauses);
        if {} in Clauses then
            return false;
        end if;
        if { k in Clauses | #k = 1 } = Clauses then
            return Clauses;
        end if;
        literal := selectLiteral(Clauses, Literals);
        Result := DavisPutnam(Clauses + {{literal}}, Literals + { literal });
        if Result /= false then
            return Result;
        end if;        
        notLiteral := negateLiteral(literal);
        return DavisPutnam(Clauses + {{notLiteral}}, Literals + { notliteral } );
    end DavisPutnam;

    procedure saturate(S);
        Units := { k in S | #k = 1 };
        Used := {};
        while Units /= {} loop
            unit := arb Units;
            Used := Used + { unit };
            literal := arb unit;
            S := reduce(S, literal);
            Units := { k in S | #k = 1 } - Used;        
        end loop;
        return S;
    end saturate;

    procedure reduce( S, l );
        notL := negateLiteral(l);
        return { k - { notL } : k in S | notL in k } + 
               { k : k in S | not notL in k and (not l in k or k = {l}) };
    end reduce;

    procedure selectLiteral( S, Forbidden );
        return arb { l : k in S, l in k | not l in Forbidden };
    end selectLiteral;

    procedure negateLiteral(l);
        if l(1) = "-" then
            return l(2);
        else
            return [ "-", l ];
        end if;
    end negateLiteral;

end main;


Angehängt noch die Datei mit Kommentaren.
Angehängte Dateien
Dateityp: txt queens.stl.txt (12,3 KB, 28x aufgerufen)
lookshe ist offline   Mit Zitat antworten
   
HaBOT
 
- Anzeige -

Werbung ist gerade online    
Alt 18.12.07, 00:23   #3 (permalink)
 
Registriert seit: 17.02.06
Harry Boeck Leistung: Facit NTK
Likes: 0
Standard

http://harryboeck.dyndns.org/Experim...Plazierung.php
http://harryboeck.dyndns.org/Experim...azierung-2.php
Harry Boeck ist offline   Mit Zitat antworten
Alt 18.12.07, 22:43   #4 (permalink)
CDW
Moderator
Themenstarter
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 202
Standard

Ich habe hier eine etwas andere Lösungsmethode ("Heuristik"). Sie liefert zwar nur eine mögliche Lösung zurück, dafür aber auch für deutlich größere n
der Trick besteht darin, eine für das jeweilige n passende Startgröße zu wählen - ist sie zu groß, wird bei kleineren n unnötig Zeit "verplempert", ist sie zu klein, wird bei größeren n zu wenig "Suchraum" abgedeckt und es dauert wiederum womöglichst viel zu lange.
Start: java Main <populationsize> <n>
Bsp: java Main 1000 8
um eine Lösung für ein 8x8 Brett zu erhalten
Erfahrungswerte:Startgröße 1000 - 10000
sehr grobe Orientierungswerte
für n=8 werden ~40ms - 260ms benötigt
n=10 ~40 bis 200ms
n=12 ~150 bis 1000ms
n=20 ~500ms bis 10s (populationsize sollte ab n>=20 auf 10000 hochgeschraubt werden)
n=50 ~ab 8sek


Main.java   

Code:
public class Main
{

	public static void main(String[] args)
	{
		try
		{
			long time = System.currentTimeMillis();
			World earth = new World(Integer.parseInt(args[0]), Integer
					.parseInt(args[1]));
			int[] result = earth.compute();
			for (int i = 0; i < result.length; i++)
			{
				for (int k = 0; k < result.length; k++)
					if (k != result[i])
						System.out.print("| ");
					else
						System.out.print("|x");
				System.out.println("|");
			}
			System.out.println(System.currentTimeMillis() - time);

		} catch (Exception ex)
		{
			System.out.println(ex.toString());
			System.out.println("Main <populationsize> <n>");
		}
	}

}

Creature.java   

Code:
import java.util.Random;

public class Creature implements Comparable <Creature>
{
	private int[] genom;
	private int fitness;
	private static Random rand=new Random();

	//dient nur der initialisierung	der Welt
	public Creature(int genomsize) 
	{
		genom = new int[genomsize];
		int temp=rand.nextInt(genomsize);
		for (int i=0;i<genom.length;i++)
			genom[i]=(temp+i)%genomsize;
		setFitness();
	}
	
	//nur die Klasse selbst darf sich vermehren 
	//führe dabei ein Crossing-Over durch
	//auch wenn es biologisch haarsträubend anmutet ;)
	private Creature(Creature mother,Creature father)
	{
		genom=new int[father.getGenom().length];
		int k=rand.nextInt(genom.length);
		int cross_len=rand.nextInt(genom.length-k);
		//Mutterchromosom
		for (int i=0;i<genom.length;i++)
			genom[i]=mother.getGenom()[i];
		for (;k<=cross_len;k++)
			genom[k]=father.getGenom()[k];	
		setFitness();		
	}

	public int compareTo(Creature cr) {return fitness-cr.getFitness();}
	
	int[] getGenom() {return genom;}
	
	public Creature makeLove(Creature father)
	{
		return new Creature(this,father);
	}
	
	public void mutate()
	{
		genom[rand.nextInt(genom.length)]=rand.nextInt(genom.length);
		setFitness();
	}
	
	public int getFitness() {return fitness;}	
	//fitnes wird schlechter, wenn die Damen in gleicher
	//spalte sind oder sich diagonal bedrohen	
	private void setFitness() 
	{
		int fit=0;
		for (int i=0;i<(genom.length-1);i++)
			for (int k=i+1;k<genom.length;k++)
			{
				if (genom[i]==genom[k]) fit++;				
				if ((k-i)==Math.abs(genom[k]-genom[i])) fit++;
			}	
		this.fitness=fit;
	}
}


World.java   

Code:
import java.util.Random;
import java.util.Vector;

public class World
{
	// Abgesehen von CHILDREN immer als 1/n Anteil an der Bevölkerung
	// zu verstehen
	private final static int BEST_REPRODUCTION = 8;
	private final static int CHILDREN = 4;
	private final static int RANDOM_REPRODUCTION = 20;
	private final static int MUTATION = 10;

	private Vector<Creature> population = new Vector<Creature>();	
	private static Random rand = new Random(0);	
	private int populationsize=0;

	public World(int populationsize, int genomsize)
	{
		this.populationsize=populationsize;
		// erschaffe eine neue Welt :)
		for (int i = 0; i < populationsize; i++)
			population.add(new Creature(genomsize));
		java.util.Collections.sort(population);
	}

	public int[] compute()
	{
		while (population.get(0).getFitness() > 0)
		{
			int actual_size = population.size();
			// fortpflanzung der "besten"
			for (int i = 0; i < actual_size / BEST_REPRODUCTION; i++)
				for (int k = 0; k < CHILDREN; k++)
				{
					population.add(population.get(i).makeLove(
							population.get(rand.nextInt(actual_size
									/ BEST_REPRODUCTION))));
				}

			// zufällige fortpflanzung
			actual_size = population.size();
			for (int i = 0; i < actual_size / RANDOM_REPRODUCTION; i++)
			{
				population.add(population.get(rand.nextInt(actual_size))
						.makeLove(population.get(rand.nextInt(actual_size))));
			}

			// mutiere (aber verschone den "besten"):
			actual_size = population.size();
			for (int i = 0; i < actual_size / MUTATION; i++)
			{
				population.get(rand.nextInt(actual_size - 1) + 1).mutate();
			}
			// jetzt lasse die Schwachen sterben:
			java.util.Collections.sort(population);
			population.setSize(populationsize);
		}
		return population.get(0).getGenom();
	}
}

Edit: eine Lösung für n=100 (ca 5 min)
Vieles hängt von den gewählten Parametern ab. Zugegebenermaßen eignet sich das Verfahren eher dazu, möglichst schnell eine suboptiomale Lösung zu erhalten - insbesondere bei dem Schritt "99% optimal -> 100%" wird es sehr deutlich.
Im Anhang die aktualierte Version+"binary"
Angehängte Dateien
Dateityp: txt loesung_fuer_n=100.txt (19,8 KB, 23x aufgerufen)
Dateityp: zip dame.zip (5,4 KB, 12x aufgerufen)
__________________
Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
Selig, wer nichts zu sagen hat und trotzdem schweigt.
CDW ist offline   Mit Zitat antworten
Alt 04.01.08, 17:18   #5 (permalink)
JTron
Guest
 
Likes:
Standard

hier, musste selbst erstmal nachdenken und im internet schauen:

Code:
class NDamen
	def initialize(size)
		@size = size
		@brett = []
	end
	def to_s
		versuch(0)
	end
private
	def feld_frei(ix, iy)
		for i in 0..iy-1
			if (@brett[i] == ix) || (((@brett[i].to_i)-ix).abs) == ((i - iy).abs)
				return false
			end
		end
		return true
	end
	def versuch(n)
		if n == @size
			print_one
		else
			for i in 0..@size-1
				if feld_frei(i,n)
					@brett[n] = i
					versuch(n+1)
				end
			end
		end
	end
	def print_one
		for i in 0..@size-1
			for j in 0..@size-1
				if j == @brett[ i ]
					print "*"
				else
					print "."
				end
			end
			print "\n"
		end
		print "\n\n"
		gets
	end
end

x = NDamen.new(8)
x.to_s
unten die n - Zahl einfügen (bei x = NDamen.new(n) )
  Mit Zitat antworten
Alt 23.03.08, 22:44   #6 (permalink)
 
Registriert seit: 22.03.08
MontyPerl Leistung: Facit NTK
Likes: 0
Standard

Nimmt als erstes Argument n an. Falls kein Argument übergeben wird, wird n von STDIN gelesen.

n-Damenproblem auf n*n-Brett in perl   
Code:
#!/usr/bin/env perl
use warnings;
use strict;

our $n;

if (@ARGV) {$n = $ARGV[0]}
else {print "\$n ="; chomp($n = <STDIN>)}

sub solveRecur {
    my ($y, $cur, $sol, @field) = @_;
    if ($y < $n) {
        for my $x (0 .. $n-1) {
            if (not isThreatened($x, $y, @field)) {
                ${field[$y][$x]} = 1;
                solveRecur($y+1, [@$cur, "$x,$y"], $sol, @field);
                ${field[$y][$x]} = 0
            }
        }
    }
    else {
        push(@{$sol}, join(';', @$cur))
    }
}

sub validConstellation {
    my ($x1, $y1, $x2, $y2) = @_;
    if (($x1 == $x2) or ($y1 == $y2)) {return 0}
    for my $dX (1, -1) {
        for my $dY (1, -1) {
            my ($tmpX, $tmpY) = ($x1, $y1);
            while(($tmpX >= 0) and ($tmpX < $n) and ($tmpY >= 0) and ($tmpY < $n)) {
                $tmpX += $dX;
                $tmpY += $dY;
                if (($tmpX == $x2) and ($tmpY == $y2)) {return 0}
            }
        }
    }
    return 1
}

sub isThreatened {
    my ($x, $y, @field) = @_;
    for my $i (0 .. $n) {
        for my $j (0 .. $n) {
            if ((${field[$i][$j]) and (not validConstellation($x, $y, $j, $i))) {return 1}
            }
        }
    }
    return 0
}

sub createField {
    my @field;
    for my $y (0 .. $n-1) {
        $field[$y] = [];
        for (0 .. $n-1) {
            push(@{$field[$y]}, 0)
        }
    }
    return @field
}


sub prepareSolvedField {
    my @field = createField();
    for my $xypair (split(/;/, $_[0])) {
        my ($x, $y) = split(/,/, $xypair);
        ${field[$y][$x]} = 1
    }
    return @field
}

sub outputField {
    my @field = @_;
    for (1 .. $n) {print "--"}
    print "\n";
    foreach my $rowRef (@field) {
        foreach my $pos (@$rowRef) {
            if ($pos) {print "\@ "}
            else {print ". "}
        }
        print "\n"
    }
}


my @solutions;
solveRecur(0, [], \@solutions, createField());

foreach my $solution (@solutions) {
    outputField(prepareSolvedField($solution))
}


?: Wer auf Farbe steht, kann die outputField Funktion mit dieser hier ersetzen:
Code:
sub outputField {
    use Term::ANSIColor qw(:constants);
    my @field = @_;
    my $switch = 1;
    for (1 .. $n) {print "--"}
    print "\n";
    foreach my $rowRef (@field) {
        foreach my $pos (@$rowRef) {
            if ($switch) {print ON_RED}
            else {print RESET}
            $switch = not $switch;
            if ($pos) {print "\@ "}
            else {print "  "}
        }
        print RESET, "\n";
        unless ($n % 2) {$switch = not $switch}
    }
}
MontyPerl ist offline   Mit Zitat antworten
Alt 23.03.08, 23:59   #7 (permalink)
Senior Member
 
Registriert seit: 03.09.05
Lesco Leistung: Facit NTK
Likes: 0
Standard

Hier noch 'ne Alternative zum Standard-Backtracking(jedoch auch nur eine Lösung pro Durchlauf): Man wählt eine zufällige Permutation und versucht diese durch Tauschen von Damen zu einer Lösung zu bringen. Damit kommt man dann sogar auf O(n^3) pro Permutation und für größere Bretter geht die Anzahl an benötigten Permutationen gegen 1.

Vorsicht: unoptimiert und unsauber:
nqueens.h   

Code:
#ifndef NQUEENS_H_
#define NQUEENS_H_
#define DEBUGV
//for debugging output, remove later
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <cstdlib>
#include <exception>

using namespace std;

class InvalidParam: public exception
{
	virtual const char* what() const throw()
  	{
    	return "Invalid parameter passed";
  	}
};

class NQueensSolver
{
	public:
		NQueensSolver(int n=8);
		vector<int> generateSolution();
	private:
		void generatePermutation(); //generates a new permutation
		bool resolveCollisions(); //tries to eliminate all collisions for the current perm.
		void countCollisions(); //counts collisions per diagonal
		int getNCollisions(int n); //gets collisions for a specified negative diagonal
		int getPCollisions(int n); //gets collisions for a specified positive diagonal
		int collisions(int n); //checks for collisions if n queens are on a diagonal
		void printVector(vector<int> v);
		vector<int> perm;
		map<int, int> queens1,queens2;
		int n;
};

#endif /*NQUEENS_H_*/


nqueens.cpp   

Code:
#include "nqueens.h"

NQueensSolver::NQueensSolver(int n)
{
	if(n<4) {
		throw InvalidParam();	
	}
	this->n = n;	
}

void NQueensSolver::printVector(vector<int> v)
{
	for(vector<int>::iterator it=v.begin();it!=v.end();it++) {
		cout << *it << endl;	
	}	
}

vector<int> NQueensSolver::generateSolution() 
{
	//cout << "Trying to generate solution for n=" << n << endl;
	bool solutionFound=false;
	int i=0;
	do {
		i++;
		generatePermutation();
		cout << "Trying permutation(Try: " << i << "): " << endl;
		printVector(perm);
		countCollisions();
		solutionFound=resolveCollisions();
	} while(!solutionFound);
	return perm;
}

void NQueensSolver::generatePermutation() 
{
	vector<int> values;
	for(int i=0;i<n;i++)
		values.push_back(i);
	perm.erase(perm.begin(),perm.end());
	for(int i=0;i<n;i++) {
		int temp = rand() % (n-i);
		perm.push_back(values[temp]);
		values.erase(values.begin()+temp);
	}
}

void NQueensSolver::countCollisions()
{
	/*
	 * check all "negative" diagonals
	 * x+y=const. for all fields on it
	 */
	for(int i=0;i<(2*n-1);i++) {
		int colls=0;
		for(int j=0;j<n;++j) {
			if((perm[j] + j) == i)
				colls++;	
		}	
		queens1[i] = colls;
	}
	/*
	 * check all "positive" diagonals
	 * x-y=const. for all fields
	 */
	 for(int i=0;i<(2*n-1);i++) {
	 		int val = i-n+1,colls=0;
	 		for(int j=0;j<n;j++) {
	 			if((j-perm[j]) == val)
	 				colls++;	
	 		}
	 		queens2[val]=colls;
	 }
}

int NQueensSolver::getNCollisions(int n)
{
	if(queens1[n] < 2)
		return 0;
	return queens1[n]-1;	
}

int NQueensSolver::getPCollisions(int n)
{
	if(queens2[n] < 2)
		return 0;
	return queens2[n]-1;	
}

int NQueensSolver::collisions(int n)
{
	if(n<2)
		return 0;
	return n-1;	
}

bool NQueensSolver::resolveCollisions()
{
	int swaps;
	do {
		swaps=0;
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				int nval1 = i + perm[i];
				int nval2 = j + perm[j];
				int pval1 = i - perm[i];
				int pval2 = j - perm[j];
				
				if(i==j)
					continue;
				//check wether one queen is attacked
				if(getNCollisions(nval1)||getPCollisions(pval1)||
					getNCollisions(nval2)||getPCollisions(pval2)) {
					int before,after;
					map<int,int> temp1(queens1),temp2(queens2);
					temp1[nval1]--; temp2[pval1]--;
					temp1[i+perm[j]]++; temp2[i-perm[j]]++;
					temp1[nval2]--; temp2[pval2]--;
					temp1[j+perm[i]]++; temp2[j-perm[i]]++;
					before = collisions(queens1[nval1]) + collisions(queens2[pval1]) +
								collisions(queens1[i+perm[j]]) + collisions(queens2[i-perm[j]]) +
								collisions(queens1[nval2]) + collisions(queens2[pval2]) +
								collisions(queens1[j+perm[i]]) + collisions(queens2[j-perm[i]]);
					after = collisions(temp1[nval1]) + collisions(temp2[pval1]) +
								collisions(temp1[i+perm[j]]) + collisions(temp2[i-perm[j]]) +
								collisions(temp1[nval2]) + collisions(temp2[pval2]) +
								collisions(temp1[j+perm[i]]) + collisions(temp2[j-perm[i]]);
							
					//swapping reduces collisions -> swap them
					if(after<before) {
							queens1[nval1]--; queens2[pval1]--;
							queens1[i+perm[j]]++; queens2[i-perm[j]]++;
							queens1[nval2]--; queens2[pval2]--;
							queens1[j+perm[i]]++; queens2[j-perm[i]]++;
							swaps++;
							int temp = perm[i];
							perm[i] = perm[j];
							perm[j] = temp;
					}
				}
			}	
		}
	} while(swaps!=0);
	for(int i=0;i<(2*n-1);i++) {
		if(queens1[i]>1)
			return false;
		if(queens2[i-n+1]>1)
			return false;		
	}
	return true;	
}


main.cpp   

Code:
#include <iostream>
#include <cstdlib>
#include <vector>
#include "nqueens.h"

using namespace std;

int main(int argc,char **argv)
{
	srand(time(0));
	int n;
	if(argc != 2) {
		cout << "USAGE: " << argv[0] << " n" << endl;
		cout << "Assuming default: n=8" <<endl;
		n = 8;
	}
	else {
		n = atoi(argv[1]);
	}
	if(n<=3) {
		cout << "Invalid Parameter" << endl;
		return 1;
	}
	
	NQueensSolver nq(n);
	vector<int> solution = nq.generateSolution();
	cout << endl;
	for(vector<int>::iterator it=solution.begin();it!=solution.end();it++) {
		cout << *it << endl;	
	}
	return 0;
}

(können "glücksbedingt" mehr oder weniger stark variieren)
n=100: 0.6s
n=1000: 21.18s
n=5000: 9:18min
Lesco ist offline   Mit Zitat antworten
Alt 24.03.08, 19:53   #8 (permalink)
 
Registriert seit: 09.08.06
shUnderdog Leistung: Facit NTK
shUnderdog eine Nachricht über Yahoo! schicken
Likes: 0
Standard

auf die gefahr hin als noob oder ähnliches hingestellt zu werden^^

woher kommt bitte die imense zeitsteigerung von 1000 auf 5000 durchläufe?
shUnderdog ist offline   Mit Zitat antworten
Alt 24.03.08, 21:36   #9 (permalink)
Senior Member
 
Registriert seit: 03.09.05
Lesco Leistung: Facit NTK
Likes: 0
Standard

Nunja, dass liegt daran, dass die Zeit nicht linear, sondern immernoch polynomiell(was schonmal ein großer Vorteil zum exponentiellen Backtracking-Algorithmus ist) ansteigt, d.h. verdoppelt man die Größe verdoppelt sich nicht die Zeit, sondern sie wächst stärker an.(Z.B. für x^3: 10^3=1000 50^3=125000)
Lesco ist offline   Mit Zitat antworten
Alt 20.06.08, 12:37   #10 (permalink)
 
Registriert seit: 21.04.08
Ook! Leistung: Facit NTK
Likes: 0
Standard

Meine Java Lösung

Code:
import java.util.ArrayList;
import java.util.List;

public class Queenproblem {
	
	public static void main(String[] args) {
		Solver solver = new Queenproblem().new Solver(8);
		System.out.println("Anzahl Lösungen: "+ solver.getSolutionCount());
		System.out.println("\n"+ solver.printFields());
	}
	
	class Solver {
		
		private int queensCount = 0;
		private List<int[][]> solutions = null; 
		
		public Solver(int queensCount){
			this.queensCount = queensCount;
			this.solutions = new ArrayList<int[][]>(); 
			this.doIt(0, 1, new int[8][8]);
		}
		
		private void doIt(int row, int queen, int[][] field){
			if(queen > queensCount){
				solutions.add(cloneField(field));
				return;
			}
			for(int i=0; i<8; i++){
				if(!isConflict(row, i, field)){
					field[row][i] = queen;
					doIt(row+1, queen+1, field);
					field[row][i] = 0;
				}
			}
		}
		
		private boolean isConflict(int row, int col, int[][] field){			
			for(int i=0; i<8; i++){
				for(int z=0; z<8; z++){
					if(field[i][z] > 0){
						if(i == row || z == col){ // selbe reihe oder selbe spalte
							return true;
						}
						else if((i-z) == (row-col)){ // selbe diagonale lo->ru
							return true;
						}
						else if((i+z) == (row+col)){ // selbe diagonale ro->lu
							return true;
						}
					}
				}
			}
			return false;
		}
		
		private int[][] cloneField(int[][] field){
			int[][] clone = new int[8][8];
			for(int i=0; i<8; i++){
				clone[i] = field[i].clone();
			}
			return clone;
		}
		
		public int getSolutionCount(){
			return solutions.size();
		}
		
		public String printFields(){
			String returnString = "";
			for(int[][] field : solutions){
				for(int[] row : field){
					for(int value : row) {
						returnString += value +" ";
					}
					returnString += "\n";
				}
				returnString += "\n";
			};
			return returnString.substring(0,returnString.length()-2);
		}
		
	}
	
}
Ook! ist offline   Mit Zitat antworten
Alt 17.08.08, 22:16   #11 (permalink)
CDW
Moderator
Themenstarter
 
Benutzerbild von CDW
 
Registriert seit: 20.07.05
CDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: OpteronCDW Leistung: Opteron
Likes: 202
Standard

BF (sucht alle Lösungen):
primitiv   

stumpfes Ausprobieren
Code:
:-use_module(library(lists)).
not_diag(_,[],_).
not_diag(X,[E|Board],Count):-X=\=E+Count,X=\=E-Count,New is Count+1,not_diag(X,Board,New).

no_err([]).
no_err([X|Board]):- not_diag(X,Board,1),no_err(Board),!.

solution(Board,Result):-permutation(Board,Result),no_err(Result).
solution(N,Res):-numlist(1,N,Board),solution(Board,[],Res).

besser   

hier werden nur die Lösungswege weiterverfolgt/Berücksichtigt, die bis dahin richtig waren (dann wird das Board weiter zusammengesetzt). Ist sogar kürzer als die primitive Lösung (da man davon ausgehen kann, dass die bisher zusammengesetzten Elemente korrekt zusammengesetzt wurden, braucht man nur das aktuell hinzugefügte Element zu prüfen - dank Rekursion lässt sich die Richtigkeit sogar sehr einfach beweisen :D )
Code:
:-use_module(library(lists)).

solution([],Result,Result).
solution(Board,Acc,Result):-select(X,Board,New_Board),
                            not_diag(X,Acc,1),
                            solution(New_Board,[X|Acc],Result).
solution(N,Res):-numlist(1,N,Board),solution(Board,[],Res).

not_diag(_,[],_).
not_diag(X,[E|Board],Count):-X=\=E+Count,X=\=E-Count,New is Count+1,not_diag(X,Board,New).

Beide sind dazu geeignet, nach allen Lösungen zu suchen (sonst kann man sich auch eine bestimmte anzeigen lassen). Nur der erste ist eben etwas langsammer
Suchen aller Lösungen (ok, ohne sie zu printen) für N=12 dauert 3 Sek, für N=13 ca. 21 Sekunden.

Aufruf mit:
solve(N,Result).
Bsp:
Zitat:
6 ?- solution(25,R).
R = [22, 17, 12, 18, 16, 14, 7, 10, 8, 6, 23, 25, 20, 24, 21, 19, 15, 13, 11, 9, 4, 2, 5, 3, 1]
oder:
findall(_,solution(8,_),Counter),length(Counter,An zahl).
Anzahl = 92.
__________________
Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
Selig, wer nichts zu sagen hat und trotzdem schweigt.
CDW ist offline   Mit Zitat antworten
Antwort
   
- Anzeige -

Werbung ist gerade online    

[HaBo] » Software Home » Code Kitchen » Programmieraufgaben » Ein Schachbrett - acht Damen
Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind aus
Pingbacks sind aus
Refbacks sind aus



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61