The Graph Coloring Problem by James Pate Williams, Jr.

The Graph Coloring Problem and N-Queens Puzzle are both NP-Complete constraint satisfaction problems. There does not exist polynomial time algorithms to solve large instances of either problem. The Graph Coloring Problem is given a graph of n-vertices and m-edges find the minimum number of colors such that no two connected vertices are of the same color. The N-Queens Puzzle is given a n-by-n chessboard and n-queens place the queens such that no two queens are attacking one another. A queen in chess can move any number of squares diagonally, horizontally, or vertically.

As a Master of Software Engineering graduate student in the era 1998 to 2000, I majored in the subdiscipline of artificial intelligence known as constraint satisfaction. I developed evolutionary hill-climbing algorithms to solve constraint satisfaction problems. I specifically solved instances of the Graph Coloring Problem and the N-Queens Puzzle. I compared my algorithms with other researchers’ algorithms. One of the algorithms tested was Makato Yokoo’s Weak-Commitment Search Algorithm (WCSA). Yakoo wrote a very nice book named “Distributed Constraint Satisfaction” which has excellent flow-charts of several algorithms including the Min-Conflicts Search Algorithm (MCSA) and his WCSA. I implemented both algorithms in the C++ and Java computer languages.

I rewrote the preceding two algorithms in the C# computer language sometime in the epoch 2008 – 2009. Below are three instances of the Graph Coloring Problem with four, eight, and twelve vertices solved by the Yakoo’s WCSA.

Numerical Two-Dimensional Quadrature (Integration) by James Pate Williams, Jr.

Back in 2022 I performed some numerical experiments using the two-dimensional quadrature methods: Simpson’s Rule and Monte Carlo. I implemented both sequential and multitasking techniques. The integration algorithms were applied to electron-electron repulsion integrals and a two-dimensional exponential function. The two-dimensional exponential function has an exact value of pi divided by 4. The multitasking speed-up is about two-fold in the Simpson’s Rule case and almost three-fold in the Monte Carlo case.

Guitar Chord and Scale Calculator by James Pate Williams, Jr. (c) 2003-2009 Now 2023

In the early 2000s I bought a hardware SNARLING DOGS GUITAR CHORD Computer. In 2003 I decided to emulate the hardware device in Java and later in 2009 C#. I have more work to do such as adding minor, augmented, diminished, sixth, seventh, and ninth chords. I require more scales such as the seventh and ninth scales.

Computation of Ulam Primes in C++ Translation from Python by James Pate Williams, Jr (c) 2008 – 2023.

http://en.wikipedia.org/wiki/Ulam_numbers

https://oeis.org/A002858

Stanislaw Marcin Ulam worked on the Manhattan Project by an invitation from John von Neumann:

https://en.wikipedia.org/wiki/Stanis%C5%82aw_Ulam#Move_to_the_United_States

Ulam is given credit for the Teller-Ulam design of the hydrogen bomb. Edward Teller was one of the first proponent of human induced global climate change:

https://en.wikipedia.org/wiki/Edward_Teller#Hydrogen_bomb

/*
	Translator: James Pate Williams, Jr. (c) 2008

	Translated to C++ from the following python code:

	http://en.wikipedia.org/wiki/Ulam_numbers
	https://oeis.org/A002858

	ulam_i = [1,2,3]
	ulam_j = [1,2,3]
	for cand in range(4,5000):
		res = []
		for i in ulam_i:
			for j in ulam_j:
				if i == j or j > i: pass
				else:
					res.append(i+j)
				if res.count(cand) == 1:
				ulam_i.append(cand)
				ulam_j.append(cand)
			print ulam_i

	Find the Ulam primes <= 5000
*/

#include "stdafx.h"
#include <time.h>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;

bool sieve[10000000];

void PopulateSieve(bool *sieve, int number) {

	// sieve of Eratosthenes

	int c, inc, i, n = number - 1;

	for (i = 0; i < n; i++)
		sieve[i] = false;

	sieve[1] = false;
	sieve[2] = true;

	for (i = 3; i <= n; i++)
		sieve[i] = (i & 1) == 1 ? true : false;

	c = 3;

	do {
		i = c * c;
		inc = c + c;

		while (i <= n) {
			sieve[i] = false;
			i += inc;
		}

		c += 2;
		while (!sieve[c])
			c++;
	} while (c * c <= n);
}

bool CountEqualOne(int number, vector<int> ulam) {
	int count = 0, i;

	for (i = 0; i < ulam.size(); i++)
		if (ulam[i] == number)
			count++;

	return count == 1;
}

void UlamNumbers(int n) {
	int candidate, i, j;
	vector<int> vI;
	vector<int> vJ;
	vector<int> UlamResult;

	PopulateSieve(sieve, 10000000);

	for (i = 1; i <= 3; i++) {
		vI.push_back(i);
		vJ.push_back(i);
	}

	for (candidate = 4; candidate <= n; candidate++) {

		UlamResult.clear();

		for (i = 0; i < vI.size(); i++) {
			int ui = vI[i];

			for (j = 0; j < vJ.size(); j++) {
				int uj = vJ[j];

				if (ui == uj || uj > ui)
					continue;

				UlamResult.push_back(ui + uj);
			}
		}

		if (CountEqualOne(candidate, UlamResult)) {
			vI.push_back(candidate);
			vJ.push_back(candidate);
		}
	}

	j = 0;

	for (i = 0; i < vI.size(); i++) {
		if (sieve[vI[i]]) {
			cout << setw(4) << vI[i] << ' ';

			if ((j + 1) % 10 == 0) {
				j = 0;
				cout << endl;
			}
			else
				j++;
		}
	}

	cout << endl;
}

int main(int argc, char * const argv[]) {
	clock_t clock0 = clock();

	cout << "Ulam sequence prime numbers < 5000" << endl << endl;
	UlamNumbers(5000);
	clock0 = clock() - clock0;
	cout << endl << endl << "seconds = ";
	cout << (double)clock0 / CLOCKS_PER_SEC << endl;
	return 0;
}

Third Blast from the Past 1999 to 2007 Mercator Map Projection Using the Open Graphics Library by James Pate Williams, Jr.

I took an advanced graphics class in the spring quarter of 1999 at Auburn University under Professor Kai Chang. We used the Open Graphics Library in the languages C/C++. I later modified my class project into a Mercator map projection application. I have attached some screen shots from the Mercator projection application.

Blast from the Past 1997 Image of a Matrix by James Pate Williams, Jr.

/*
  Author:  Pate Williams (c) 1997

  "Algorithm 2.3.2 (Image of a Matrix). Given an
  m by n matrix M = (m[i][i]) with 1 <= i <= m and
  1 <= j <= n having coefficients in the field K,
  this algorithm outputs a basis of the image of
  M, i. e. vector space spanned by the columns of
  M." -Henri Cohen- See "A Course in Computational
  Algebraic Number Theory" by Henri Cohen pages
  58-59. We specialize the code to the field Zp.
*/

#include <stdio.h>
#include <stdlib.h>

long** create_matrix(long m, long n)
{
    long i, ** matrix = (long**)calloc(m, sizeof(long*));

    if (!matrix) {
        fprintf(stderr, "fatal error\ninsufficient memory\n");
        fprintf(stderr, "from create_matrix\n");
        exit(1);
    }
    for (i = 0; i < m; i++) {
        matrix[i] = (long*)calloc(n, sizeof(long));
        if (!matrix[i]) {
            fprintf(stderr, "fatal error\ninsufficient memory\n");
            fprintf(stderr, "from create_matrix\n");
            exit(1);
        }
    }
    return matrix;
}

void delete_matrix(long m, long** matrix)
{
    long i;

    for (i = 0; i < m; i++) free(matrix[i]);
    free(matrix);
}

void Euclid_extended(long a, long b, long* u,
    long* v, long* d)
{
    long q, t1, t3, v1, v3;

    *u = 1, * d = a;
    if (b == 0) {
        *v = 0;
        return;
    }
    v1 = 0, v3 = b;
#ifdef DEBUG
    printf("----------------------------------\n");
    printf(" q    t3   *u   *d   t1   v1   v3\n");
    printf("----------------------------------\n");
#endif
    while (v3 != 0) {
        q = *d / v3;
        t3 = *d - q * v3;
        t1 = *u - q * v1;
        *u = v1, * d = v3;
#ifdef DEBUG
        printf("%4ld %4ld %4ld ", q, t3, *u);
        printf("%4ld %4ld %4ld %4ld\n", *d, t1, v1, v3);
#endif
        v1 = t1, v3 = t3;
    }
    *v = (*d - a * *u) / b;
#ifdef DEBUG
    printf("----------------------------------\n");
#endif
}

long inv(long number, long modulus)
{
    long d, u, v;

    Euclid_extended(number, modulus, &u, &v, &d);
    if (d == 1) return u;
    return 0;
}

void image(long m, long n, long p,
    long** M, long** X, long* r)
{
    int found;
    long D, i, j, k, s;
    long* c = (long*)calloc(m, sizeof(long));
    long* d = (long*)calloc(n, sizeof(long));
    long** N = create_matrix(m, n);

    if (!c || !d) {
        fprintf(stderr, "fatal error\ninsufficient memory\n");
        fprintf(stderr, "from kernel\n");
        exit(1);
    }
    for (i = 0; i < m; i++) {
        c[i] = -1;
        for (j = 0; j < n; j++) N[i][j] = M[i][j];
    }
    *r = 0;
    for (k = 0; k < n; k++) {
        found = 0, j = 0;
        while (!found && j < m) {
            found = M[j][k] != 0 && c[j] == -1;
            if (!found) j++;
        }
        if (found) {
            D = p - inv(M[j][k], p);
            M[j][k] = p - 1;
            for (s = k + 1; s < n; s++)
                M[j][s] = (D * M[j][s]) % p;
            for (i = 0; i < m; i++) {
                if (i != j) {
                    D = M[i][k];
                    M[i][k] = 0;
                    for (s = k + 1; s < n; s++) {
                        M[i][s] = (M[i][s] + D * M[j][s]) % p;
                        if (M[i][s] < 0) M[i][s] += p;
                    }
                }
            }
            c[j] = k;
            d[k] = j;
        }
        else {
            *r = *r + 1;
            d[k] = -1;
        }
    }
    for (j = 0; j < m; j++) {
        if (c[j] != -1) {
            for (i = 0; i < n; i++) {
                if (i < m) X[i][j] = N[i][c[j]];
                else X[i][j] = 0;
            }
        }
    }
    delete_matrix(m, N);
    free(c);
    free(d);
}

void print_matrix(long m, long n, long** a)
{
    long i, j;

    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)
            printf("%2ld ", a[i][j]);
        printf("\n");
    }
}

int main(void)
{
    long i, j, m = 8, n = 8, p = 13, r;
    long a[8][8] = { {0,  0,  0,  0,  0,  0,  0,  0},
                    {2,  0,  7, 11, 10, 12,  5, 11},
                    {3,  6,  3,  3,  0,  4,  7,  2},
                    {4,  3,  6,  4,  1,  6,  2,  3},
                    {2, 11,  8,  8,  2,  1,  3, 11},
                    {6, 11,  8,  6,  2,  6, 10,  9},
                    {5, 11,  7, 10,  0, 11,  6, 12},
                    {3,  3, 12,  5,  0, 11,  9, 11} };
    long** M = create_matrix(m, n);
    long** X = create_matrix(n, n);

    for (i = 0; i < m; i++)
        for (j = 0; j < n; j++)
            M[i][j] = a[j][i];
    printf("the original matrix is as follows:\n");
    print_matrix(m, n, M);
    image(m, n, p, M, X, &r);
    printf("the image of the matrix is as follows:\n");
    print_matrix(n, n - r, X);
    printf("the rank of the matrix is: %ld\n", n - r);
    delete_matrix(m, M);
    delete_matrix(n, X);
    return 0;
}

Scale Model Construction Suggestions by James Pate Williams, Jr.

  1. After opening the box and making sure all pieces are on their numbered tree (sprue), read and study all the instructions.
  2. I like to paint the pieces while the part is on its tree.
  3. Make notes by grouping the pieces by color.
  4. I like to use acrylic paints nowadays (way back when I used enamel and enamel aerosol spray cans). Acrylic paint is easy to clean up and cures (completely dries) faster than enamel paint.
  5. Do subassemblies according to the instructions. Sometimes it is good to look ahead and make sure the assembly is facile.
  6. Do not wait until the model is finished to apply decals.
  7. Not everyone will have the artistic talent  to create a museum worthy model. Be satisfied with your current modeling ability. Happy scale modeling!

I took up plastic scale modeling again in about 2017 at the age of around 64. Here is a list of my models and some notes about their construction. All of my relatively modern models are by Revell:

  1. USS Arizona – To accurately build the hull tape off the armor belt and apply black paint. This model was painted with Testors enamel paint.
  2. USAAF B-17G Flying Fortress heavy bomber 1:48 scale. Use rubber bands and clothes pins to make sure the fuselage halves seal nicely.
  3. USN or USMC Vought F4U Corsair 1:48 scale. Be careful with the undercarriage. The landing gear is especially tricky to get correct.
  4. USAF Fairchild Republic A-10 Thunderbolt II “Warthog” 1:48 scale. I have not applied the plethora of decals. Please counterweights in the nose so the tricycle landing gear is accurate.
  5. McDonnell Douglas USMC or USN F/A-18 Hornet. Tricky landing gear assembly.
  6. Kriegsmarine Bismarck 1:350 scale. Many very small parts.
  7. Lockheed SR-71 Blackbird 1:48 scale. Lots of rather small decals. You can build different “Articles” (CIA lingo for the A-12 Archangel [Oxcart, Cygnus] and SR-71). The red no step decals are especially tricky to apply. Uses a lot of black paint.
  8. Apollo 11 Saturn V with the command module and lunar excursion module (LEM) 1:144 scale. Comes with three to scale engineers.
  9. USAAF Northup P-61 Black Widow 1:48 scale. The model comes in black plastic, so I did not paint the exterior. The radar in the nose is hard to get correctly seated.
  10. North American B-25J Mitchell medium bomber 1:48 scale. I am still working on this model.

If you have plenty of cash and patience, you can use spray paint. I prefer the somewhat inexpensive brush painting.

First Blast from the Past (1997) Computing the Inverse Image of a Matrix by James Pate Williams, Jr.

/*
  Author:  Pate Williams (c) 1997

  "Algorithm 2.3.5 (Inverse Image Matrix). Let M be
  an m by n matrix and V be an m by r matrix, where
  n <= m. This algorithm either outputs a message
  saying that some column vector of V is not in the
  image of M, or outputs an n by r matrix X such
  that V = MX." -Henri Cohen- See "A Course in Com-
  putational Algebraic Number Theory" by Henri
  Cohen pages 60-61. We specialize to the field Q.
*/

#include <stdio.h>
#include <stdlib.h>

double** create_matrix(long m, long n)
{
    double** matrix = (double**)calloc(m, sizeof(double*));
    long i;

    if (!matrix) {
        fprintf(stderr, "fatal error\ninsufficient memory\n");
        fprintf(stderr, "from create_matrix\n");
        exit(1);
    }
    for (i = 0; i < m; i++) {
        matrix[i] = (double*)calloc(n, sizeof(double));
        if (!matrix[i]) {
            fprintf(stderr, "fatal error\ninsufficient memory\n");
            fprintf(stderr, "from create_matrix\n");
            exit(1);
        }
    }
    return matrix;
}

void delete_matrix(long m, double** matrix)
{
    long i;

    for (i = 0; i < m; i++) free(matrix[i]);
    free(matrix);
}

void inverse_image_matrix(long m, long n, long r,
    double** M, double** V,
    double** X)
{
    double ck, d, sum, t;
    double** B = create_matrix(m, r);
    int found;
    long i, j, k, l;

    for (i = 0; i < m; i++)
        for (j = 0; j < r; j++)
            B[i][j] = V[i][j];
    for (j = 0; j < n; j++) {
        found = 0, i = j;
        while (!found && i < m) {
            found = M[i][j] != 0;
            if (!found) i++;
        }
        if (!found) {
            fprintf(stderr, "fatal error\nnot linearly independent\n");
            fprintf(stderr, "from inverse_image_matrix\n");
            exit(1);
        }
        if (i > j) {
            for (l = 0; l < n; l++)
                t = M[i][l], M[i][l] = M[j][l], M[j][l] = t;
            for (l = 0; l < r; l++)
                t = B[i][l], B[i][l] = B[j][l], B[j][l] = t;
        }
        d = 1.0 / M[j][j];
        for (k = j + 1; k < m; k++) {
            ck = d * M[k][j];
            for (l = j + 1; l < n; l++)
                M[k][l] -= ck * M[j][l];
            for (l = 0; l < r; l++)
                B[k][l] -= ck * B[j][l];
        }
    }
    for (i = n - 1; i >= 0; i--) {
        for (k = 0; k < r; k++) {
            sum = 0;
            for (j = i + 1; j < n; j++)
                sum += M[i][j] * X[j][k];
            X[i][k] = (B[i][k] - sum) / M[i][i];
        }
    }
    for (k = n + 1; k < m; k++) {
        for (j = 0; j < r; j++) {
            sum = 0;
            for (i = 0; i < n; i++)
                sum += M[k][i] * X[i][j];
            if (sum != B[k][j]) {
                fprintf(stderr, "fatal error\ncolumn not in image\n");
                fprintf(stderr, "from inverse_image_matrix\n");
                exit(1);
            }
        }
    }
    delete_matrix(m, B);
}

void matrix_multiply(long m, long n, long r,
    double** a, double** b,
    double** c)
    /* c = a * b */
{
    double sum;
    long i, j, k;

    for (i = 0; i < m; i++) {
        for (j = 0; j < r; j++) {
            sum = 0.0;
            for (k = 0; k < n; k++)
                sum += a[i][k] * b[k][j];
            c[i][j] = sum;
        }
    }
}

void print_matrix(long m, long n, double** a)
{
    long i, j;

    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)
            printf("%+10.6lf ", a[i][j]);
        printf("\n");
    }
}

int main(void)
{
    long i, j, m = 4, n = 4, r = 4;
    double** c = create_matrix(m, n);
    double** M = create_matrix(m, n);
    double** V = create_matrix(m, r);
    double** X = create_matrix(n, r);

    for (i = 0; i < m; i++) {
        c[i][i] = M[i][i] = 2.0;
        if (i > 0)
            c[i][i - 1] = M[i][i - 1] = -1.0;
        if (i < m - 1)
            c[i][i + 1] = M[i][i + 1] = -1.0;
    }
    for (i = 0; i < m; i++)
        for (j = 0; j < r; j++)
            V[i][j] = i + j + 1;
    printf("M is as follows:\n");
    print_matrix(m, n, M);
    printf("V is as follows:\n");
    print_matrix(m, r, V);
    inverse_image_matrix(m, n, r, M, V, X);
    printf("X is as follows:\n");
    print_matrix(n, r, X);
    matrix_multiply(m, n, r, c, X, M);
    printf("MX is as follows:\n");
    print_matrix(m, r, M);
    delete_matrix(m, c);
    delete_matrix(m, M);
    delete_matrix(m, V);
    delete_matrix(n, X);
    return 0;
}

Back-marking Algorithm for the N-Queens Problem

Back in the year 1999 I studied Constraint Satisfaction Problems (CSPs) which is a branch of the computer science discipline artificial intelligence (AI). I took a course in Artificial Intelligence and then a Machine Learning course both under Professor Gerry V. Dozier at Auburn University in the Winter and Spring Quarters of 1999. Professor Dozier was my Master of Software Engineering degree advisor. The N-Queens Problem is a constraint satisfaction problem within the setting of a N-by-N chessboard with the queens arranged such the no queens are attacking any other queens. The N-Queens Problem is believed to be a NP-Complete Problem which means only non-deterministic polynomial time algorithms solve the problem. I bought copies of Foundations of Constraint Satisfaction by E. P. K. Tsang for Professor Dozier and me in 2000. The back-marking algorithm is found in section 5.4.3 page 147 of the textbook. I implemented several algorithms from the textbook. Below is the source code for the back-marking algorithm and single runs from N = 4 to N = 12. A single run is not a statistically significantly experiment. Generally, 30 or more experimental trials are needed for statistical significance.

/*
	Author:	James Pate Williams, Jr. (c) 2000 - 2023

	Backmarking algorithm applied to the N-Queens CSP.
	Algorithm from _Foundations of Constraint Satisfaction_
	by E. P. K. Tsang section 5.4.3 page 147.
*/

#include <iomanip>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <vector>
#include <chrono>
using namespace std::chrono;
using namespace std;

// https://www.geeksforgeeks.org/measure-execution-time-function-cpp/

int constraintsViolated(vector<int>& Q) {
	int a, b, c = 0, i, j, n;

	n = Q.size();
	for (i = 0; i < n; i++) {
		a = Q[i];
		for (j = 0; j < n; j++) {
			b = Q[j];
			if (i != j && a != -1 && b != -1) {
				if (a == b) c++;
				if (i - j == a - b || i - j == b - a) c++;
			}
		}
	}
	return c;
}

bool satisfies(int x, int v, int y, int vp) {
	if (x == y) return false;
	if (v == vp) return false;
	if (x - y == v - vp || x - y == vp - v) return false;
	return true;
}

bool Compatible(int x, int v, int* LowUnit, int* Ordering, int** Mark,
	vector<int> compoundLabel) {
	bool compat = true;
	int vp, y = LowUnit[x];

	while (Ordering[y] < Ordering[x] && compat) {
		if (compoundLabel[y] != -1) {
			vp = compoundLabel[y];
			if (satisfies(x, v, y, vp))
				y = Ordering[y] + 1;
			else
				compat = false;
		}
	}
	Mark[x][v] = Ordering[y];
	return compat;
}

bool BM1(int Level, int* LowUnit, int* Ordering, int** Mark,
	vector<int> unlabelled, vector<int> compoundLabel, vector<int>& solution) {
	bool result;
	int i, v, x, y;
	vector<int> Dx(compoundLabel.size());

	if (unlabelled.empty()) {
		for (i = 0; i < (int)compoundLabel.size(); i++)
			solution[i] = compoundLabel[i];
		return true;
	}
	for (i = 0; i < (int)unlabelled.size(); i++) {
		x = unlabelled[i];
		if (Ordering[x] == Level) break;
	}
	result = false;
	for (i = 0; i < (int)compoundLabel.size(); i++)
		Dx[i] = i;
	do {
		// pick a random value from domain of x
		i = rand() % Dx.size();
		v = Dx[i];
		vector<int>::iterator vIterator = find(Dx.begin(), Dx.end(), v);
		Dx.erase(vIterator);
		if (Mark[x][v] >= LowUnit[x]) {
			if (Compatible(x, v, LowUnit, Ordering, Mark, compoundLabel)) {
				compoundLabel[x] = v;
				vIterator = find(unlabelled.begin(), unlabelled.end(), x);
				unlabelled.erase(vIterator);
				result = BM1(Level + 1, LowUnit, Ordering, Mark,
					unlabelled, compoundLabel, solution);
				if (!result) {
					compoundLabel[x] = -1;
					unlabelled.push_back(x);
				}
			}
		}
	} while (!Dx.empty() && !result);
	if (!result) {
		LowUnit[x] = Level - 1;
		for (i = 0; i < (int)unlabelled.size(); i++) {
			y = unlabelled[i];
			LowUnit[y] = LowUnit[y] < Level - 1 ? LowUnit[y] : Level - 1;
		}
	}
	return result;
}

bool Backmark1(vector<int> unlabelled, vector<int> compoundLabel, vector<int>& solution) {
	int i, n = compoundLabel.size(), v, x;
	int* LowUnit = new int[n];
	int* Ordering = new int[n];
	int** Mark = new int* [n];

	for (i = 0; i < n; i++)
		Mark[i] = new int[n];
	i = 0;
	for (x = 0; x < n; x++) {
		LowUnit[x] = 0;
		for (v = 0; v < n; v++)
			Mark[x][v] = 0;
		Ordering[x] = i++;
	}
	return BM1(0, LowUnit, Ordering, Mark, unlabelled, compoundLabel, solution);
}

void printSolution(vector<int>& solution) {
	char hyphen[256] = { '\0' };
	int column, i, i4, n = solution.size(), row;

	if (n <= 12) {
		for (i = 0; i < n; i++) {
			i4 = i * 4;
			hyphen[i4 + 0] = '-';
			hyphen[i4 + 1] = '-';
			hyphen[i4 + 2] = '-';
			hyphen[i4 + 3] = '-';
		}
		i4 = i * 4;
		hyphen[i4 + 0] = '-';
		hyphen[i4 + 1] = '\n';
		hyphen[i4 + 2] = '\0';
		for (row = 0; row < n; row++) {
			column = solution[row];
			cout << hyphen;
			for (i = 0; i < column; i++)
				cout << "|   ";
			cout << "| Q ";
			for (i = column + 1; i < n; i++)
				cout << "|   ";
			cout << '|' << endl;
		}
		cout << hyphen;
	}
	else
		for (row = 0; row < n; row++)
			cout << row << ' ' << solution[row] << endl;
}

int main(int argc, char* argv[]) {
	while (true)
	{
		int i, n;
		cout << "Number of queens (4 - 12) (0 to quit): ";
		cin >> n;
		if (n == 0)
			break;
		if (n < 4 || n > 12)
		{
			cout << "Illegal number of queens" << endl;
			continue;
		}
		auto start = high_resolution_clock::now();
		vector<int> compoundLabel(n, -1), solution(n, -1), unlabelled(n);
		for (i = 0; i < n; i++)
			unlabelled[i] = i;
		if (Backmark1(unlabelled, compoundLabel, solution))
			printSolution(solution);
		else
			cout << "problem has no solution" << endl;
		auto stop = high_resolution_clock::now();
		auto duration = duration_cast<microseconds>(stop - start);
		cout << "Runtime: " << setprecision(3) << setw(5)
			<< (double)duration.count() / 1.0e3 << " milliseconds" << endl;
	}
	return 0;
}