Bellman Ford Display predecessor for every iterations [closed] - java

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Here the predecessor vertices get displayed for all iterations. I want the final predecessor to be displayed for the vertices
import java.io.*;
import java.util.*;
public class BellmanFord {
LinkedList<Edge> edges;
int d[];
int n,e,s;
final int INFINITY=999;
private static class Edge {
int u,v,w;
public Edge(int a, int b, int c){
u=a;
v=b;
w=c;
}
BellmanFord() throws IOException{
int item;
edges=new LinkedList<Edge>();
BufferedReader inp = new BufferedReader (new InputStreamReader(System.in));
System.out.print("Enter number of vertices ");
n=Integer.parseInt(inp.readLine());
System.out.println("Cost Matrix");
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
item=Integer.parseInt(inp.readLine());
if(item!=0)
edges.add(new Edge(i,j,item));
}
e=edges.size();
d=new int[n];
System.out.print("Enter the source vertex ");
s=Integer.parseInt(inp.readLine());
}
void relax() {
int i,j;
for(i=0;i<n;++i)
d[i]=INFINITY;;
d[s] = 0;
for (i = 0; i < n - 1; ++i)
for (j = 0; j < e; ++j)
if (d[edges.get(j).u] + edges.get(j).w < d[edges.get(j).v])
{
d[edges.get(j).v] = d[edges.get(j).u] + edges.get(j).w;
/*Gives me the predecessor nodes of all iterations How can i get the final predecessornodes*/ System.out.println(edges.get(j).v+" Has predecessor " + edges.get(j).u);
}
}
boolean cycle() {
int j;
for (j = 0; j < e; ++j)
if (d[edges.get(j).u] + edges.get(j).w < d[edges.get(j).v])
return false;
return true;
}
public static void main(String args[]) throws IOException {
BellmanFord r=new BellmanFord();
r.relax();
if(r.cycle())
for(int i=0;i<r.n;i++)
System.out.println(r.s+"to"+i+" ==> "+r.d[i]);
else
System.out.println(" There is a nagative edge cycle ");
}
}
The erronous output is as follows. I am trying to print out the predecessor for every iterations:
**OUTPUT:**
Enter number of vertices
Cost Matrix
0
-1
4
0
0
0
0
3
2
2
0
0
0
0
0
0
1
5
0
0
0
0
0
-3
0
Enter the source vertex
1 Has predecessor 0
2 Has predecessor 0
2 Has predecessor 1
3 Has predecessor 1
4 Has predecessor 1
3 Has predecessor 4
0to0 ==> 0
0to1 ==> -1
0to2 ==> 2
0to3 ==> -2
0to4 ==> 1

Seems that your last lines are very less understandable and so I give you my program which I made a few days back.. you can look for the mistake your program makes since its difficult to understand 100 lines of code and find out errors :Also I advice you to focus more on writing neat and commented codes rather than straightaway focussing on time optimizations. Only check the logic and try to implement it in your code ,that's why I didn't post a Java code so that you could get everything easily :)
// A C / C++ program for Bellman-Ford's single source shortest path algorithm.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
// a structure to represent a weighted edge in graph
struct Edge
{
int src, dest, weight;
};
// a structure to represent a connected, directed and weighted graph
struct Graph
{
// V-> Number of vertices, E-> Number of edges
int V, E;
// graph is represented as an array of edges.
struct Edge* edge;
};
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
graph->V = V;
graph->E = E;
graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
return graph;
}
// A utility function used to print the solution
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
// The main function that finds shortest distances from src to all other
// vertices using Bellman-Ford algorithm. The function also detects negative
// weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
// Step 1: Initialize distances from src to all other vertices as INFINITE
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
// Step 2: Relax all edges |V| - 1 times. A simple shortest path from src
// to any other vertex can have at-most |V| - 1 edges
for (int i = 1; i <= V-1; i++)
{
for (int j = 0; j < E; j++)
{
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
// Step 3: check for negative-weight cycles. The above step guarantees
// shortest distances if graph doesn't contain negative weight cycle.
// If we get a shorter path, then there is a cycle.
for (int i = 0; i < E; i++)
{
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] + weight < dist[v])
printf("Graph contains negative weight cycle");
}
printArr(dist, V);
return;
}
// Driver program to test above functions
int main()
{
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V, E);
// add edge 0-1
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;
// add edge 0-2
graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;
// add edge 1-2
graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;
// add edge 1-3
graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;
// add edge 1-4
graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;
// add edge 3-2
graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;
// add edge 3-1
graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;
// add edge 4-3
graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;
BellmanFord(graph, 0);
return 0;
}

Related

Floyd's shortest path for undirected graph

I have implemented an program that can calculate shortest path's for any graph either by using Floyd's/Dijkstra's algorithm based on user input.
Both algorithm's work fine for directed graph.
The output is supposed to display
1)The actual path to be taken from the start vertex
2)The shortest distance to be travelled
But when it come's to undirected graph I run into problems.
My graph is not represented by an adjacency matrix but with an Graph & Edge classes as shown below
class Graph
{
private final int noOfVertices;
private final ArrayList<Edge> edges = new ArrayList<Edge>();
private boolean undirected = false;
Graph(int vertexCount)
{
noOfVertices = vertexCount;
edges.ensureCapacity(2 * (vertexCount - 1));
}
public int getWeight(int src,int dst)
{
int weight=90000;
for(Edge edge:edges)
{
if(edge.src==src && edge.dst==dst)
{
weight=edge.weight;
break;
}
}
return weight;
}
public int getEdgeCount(){return edges.size();}
public int getVertexCount(){return noOfVertices;}
public static class Edge
{
public int src;
public int dst;
public int weight;
Edge(int v1, int v2, int w)
{
src = v1;
dst = v2;
weight = w;
}
}
}
To implement undirected graph this is the code used below
void newEdge(int src,int dst,int weight)
{
edges.add(new Edge(src,dst,weight));
if(undirected){ edges.add(new Edge(dst,src,weight));}
}
Now Dijkstra's algorithm work's fine on this setup but when I use Floyd's algorithm I start to get incorrect path's but correct distance's
This is my Floyd's algorithm
public static Integer[] Floyd(Graph graph, int startVertex, int endVertex)
{
ArrayList<Integer> pathInfo = new ArrayList<Integer>();
int dist[][] = new int[graph.getVertexCount()][graph.getVertexCount()];
int path[][] = new int[graph.getVertexCount()][graph.getVertexCount()];
int V = graph.getVertexCount();
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
if (i == j)
{
dist[i][j] = 0;
}
else
{
dist[i][j] = graph.getWeight(i, j);
}/*Initialize with edge weight's between vertices i,j.If edge does not exist graph.getWeight() return's 90000 i.e simply an value somewhat close to infinite because when I use Integer.MAX_VALUE I get negative distance's when doing dist[i][k]+dist[k][j] so i avoid it*/
path[i][j] = j;
}
}
/*actual Floyd's algorithm*/
for (int k = 0; k < V; k++)
{
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
if (dist[i][j] > dist[i][k] + dist[k][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = k; /*if path exist's record the intermediate vertex*/
}
}
}
}
int currentVertex=endVertex; /*Start from last vertex*/
int nextVertex=path[startVertex][endVertex];/*Find path*/
pathInfo.add(currentVertex);/*Add Current Vertex*/
while(currentVertex!=nextVertex)/*Backtrack until the vertex we are currently at and the next vertex we need to go to from there are the same which mean's we have reached our target*/
{
currentVertex=nextVertex;
pathInfo.add(0,currentVertex);
nextVertex=path[startVertex][nextVertex];
}
pathInfo.add(0,startVertex);/*Finally add the vertex we ended at*/
pathInfo.add(dist[startVertex][endVertex]);/*Come's out correct in both cases*/
return pathInfo.toArray(new Integer[]{});/*Convert info to array*/
}
So here is my undirected graph given below.
The doted lines represent's an edge that goes in both direction's.
0--1--2--3
Each edge has an weight of 2
Now when I call Floyd's algorithm with start vertex=0 and end vertex=3
I get The correct output path.
0,1,2,3
But when I again call Floyd's algorithm with start Vertex=3 and end Vertex=0
The output path is
3,2,0
Vertex 1 is missing.
But with Dijkstra's algorithm I get the correct result's in both cases
Here is the path matrix calculated above.
0 1 1 2
0 1 2 2
1 1 2 3
2 2 2 3
The distance come's out correct that is 6 in both cases but the path is wrong when I reverse the vertex order only for Floyd's algorithm.
Most of the video ideas were incorporated from this link
https://www.bing.com/videos/search?q=floyd%27s+algorithm&&view=detail&mid=E17F409B3AB0B2307233E17F409B3AB0B2307233&&FORM=VRDGAR
Any idea's on where I went wrong?

Find the max path from root to leaf of a n-ary tree without including values of two adjacent nodes in the sum

I recently got interviewed and was asked the following question.
Given an n-ary tree, find the maximum path from root to leaf such that maximum path does not contain values from any two adjacent nodes.
(Another edit: The nodes would only have positive values.)
(Edit from comments: An adjacent node means node that share a direct edge. Because its a tree, it means parent-child. So if I include parent, I can not include child and vice versa.)
For example:
5
/ \
8 10
/ \ / \
1 3 7 9
In the above example, the maximum path without two adjacent would be 14 along the path 5->10->9. I include 5 and 9 in the final sum but not 10 because it would violate the no two adjacent nodes condition.
I suggested the following algorithm. While I was fairly sure about it, my interviewer did not seem confident about it. Hence, I wanted to double check if my algorithm was correct or not. It seemed to work on various test cases I could think of:
For each node X, let F(X) be the maximum sum from root to X without two adjacent values in the maximum sum.
The formula for calculating F(X) = Max(F(parent(X)), val(X) + F(grandParent(X)));
Solution would have been
Solution = Max(F(Leaf Nodes))
This was roughly the code I came up with:
class Node
{
int coins;
List<Node> edges;
public Node(int coins, List<Node> edges)
{
this.coins = coins;
this.edges = edges;
}
}
class Tree
{
int maxPath = Integer.MIN_VALUE;
private boolean isLeafNode(Node node)
{
int size = node.edges.size();
for(int i = 0; i < size; i++)
{
if(node.edges.get(i) != null)
return false;
}
return true;
}
// previous[0] = max value obtained from parent
// previous[1] = max value obtained from grandparent
private void helper(Node node, int[] previous)
{
int max = Math.max(previous[0], max.val + previous[1]);
//leaf node
if(isLeafNode(node))
{
maxPath = Math.max(maxPath, max);
return;
}
int[] temp= new int[2];
temp[0] = max;
temp[1] = prev[0];
for(int i = 0; i < node.edges.size(); i++)
{
if(node.edges.get(i) != null)
{
helper(node.edges.get(i), temp);
}
}
}
public int findMax(Node node)
{
int[] prev = new int[2];
prev[0] = 0;
prev[1] = 0;
if(node == null) return 0;
helper(node, prev);
return maxPath;
}
}
Edit: Forgot to mention that my primary purpose in asking this question is to know if my algorithm was correct rather than ask for a new algorithm.
Edit: I have a reason to believe that my algorithm should also have worked.
I was scouring the internet for similar questions and came across this question:
https://leetcode.com/problems/house-robber/?tab=Description
It is pretty similar to the problem above except that it is now an array instead of the tree.
The formal F(X) = Max(F(X-1), a[x] + F(X-2)) works in this case.
Here is my accepted code:
public class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length];
if(nums.length < 1) return 0;
dp[0] = nums[0];
if(nums.length < 2) return nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < nums.length; i++)
{
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[nums.length-1];
}
}
The natural solution would be to compute for each node X two values: max path from X to leaf including X and max path from X to leaf, excluding X, let's call them MaxPath(X) and MaxExcluded(X).
For leaf L MaxPath(L) is Value(L) and MaxExcluded(L) is 0.
For internal node X:
MaxPath(X) = Value(X) + Max over child Y of: MaxExcluded(Y)
MaxExcluded(X) = Max over child Y of : Max(MaxExcluded(Y), MaxPath(Y))
The first line means that if you include X, you have to exclude its children. The second means that if you exclude X, you are free to either include or exclude its children.
It's a simple recursive function on nodes which can be computed going leaves-to-parents in O(size of the tree).
Edit: The recursive relation does also work top-down, and in this case you can indeed eliminate storing two values by the observation that MaxExcluded(Y) is actually MaxPath(Parent(Y)), which gives the solution given in the question.
Implementation of what #RafałDowgird explained.
/* 5
* 8 10
* 1 3 7 9
* 4 5 6 11 13 14 3 4
*
*
*/
public class app1 {
public static void main(String[] args) {
Node root = new Node(5);
root.left = new Node(8);root.right = new Node(10);
root.left.left = new Node(1);root.left.right = new Node(3);
root.right.left = new Node(7);root.right.right = new Node(9);
root.left.left.left = new Node(4);root.left.left.right = new Node(5);
root.left.right.left = new Node(6);root.left.right.right = new Node(11);
root.right.left.left = new Node(13);root.right.left.right = new Node(14);
root.right.right.right = new Node(4);
System.out.println(findMaxPath(root));
}
private static int findMaxPath(Node root) {
if (root == null) return 0;
int maxInclude = root.data + findMaxPathExcluded(root);
int maxExcludeLeft = Math.max(findMaxPath(root.left), findMaxPathExcluded(root.left));
int maxExcludeRight = Math.max(findMaxPath(root.right), findMaxPathExcluded(root.right));
return Math.max(maxInclude, Math.max(maxExcludeLeft, maxExcludeRight));
}
private static int findMaxPathExcluded(Node root) {
if(root == null) return 0;
int left1 = root.left!=null ? findMaxPath(root.left.left) : 0;
int right1 = root.left!=null ? findMaxPath(root.left.right) : 0;
int left2 = root.right!=null ? findMaxPath(root.right.left) : 0;
int right2 = root.right!=null ? findMaxPath(root.right.right) : 0;
return Math.max(left1, Math.max(right1, Math.max(left2, right2)));
}
}
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data=data;
}
}

Generate Random Symmetric Weighted Adjacency Matrix

I'm trying to test implementations of Prim's and Kruskal's algorithm by using a cost adjacency matrix. I'm generating these matrices on the amount of vertices in the graph, and the amount of edges in the graph. It does not have to be a connected graph.
Here's what I have so far:
final static int infinity = 2000000000;
public static int[][] genAdjMat(int V, int E) {
int[][] a = new int[V][V];
int e = E;
for(int i = 0; i < V; i++) {
for(int j = i; j < V; j++) {
if(i == j) {
a[i][j] = 0;
}
else {
if(Math.random() < 0.5 && e >= 0) {
int temp = (int)Math.ceil(Math.random()*e);
a[i][j] = temp;
a[j][i] = temp;
e--;
}
else {
a[i][j] = infinity;
a[j][i] = infinity;
}
}
}
}
return a;
}
Right now, it generates a symmetric array but it doesn't use all the edges that I specify. I'm having trouble figuring out how to use up all the edges and still have them randomly placed throughout the matrix while maintaining symmetry.
I'd suggest the following:
Generate the list of all possible undirected edges (V * (V - 1) / 2 items).
Shuffle it.
Pick the first E edges.
Straight forward: just generate the edges independently.
Random random = new Random();
Set<Map.Entry<Integer,Integer>> edges = Sets.newHashSet();
for (int i=0; i<e; i++) {
do {
int xCoordinate = random.nextInt(V);
int yCoordinate = random.nextInt(V);
} while(!edges.add(xCoordinate, yCoordinate));
}
Now use the edges to put them in your matrix.
Alternatively (while iterating over the matrix), use the following probability function: p(A[i,j] == 1) = (e - k) / (V^2 - (i * V + j)). Where k is the number of already assigned edges. The point of this is - have a probability less then 1 while the number of entries that are remaining is still higher then the number of edges you have to assign, this becomes 1 when the number of edges you still have to assign is equal to remaining entries to iterate over.

Dijkstra's Algorithm Java-- Distance not right

I am trying to code dijkstra's algorithm, starting at any vertex I need to show the distance and print the path of nodes. It works for vertex 2,4, and 5, but for 1 and 3 it gets messed up. It's probably something stupidly small, but I can't see it.
public static void main(String[] args)
{
int INF = Integer.MAX_VALUE;
int verticies = 5;
int W[][] = {{INF,7,4,6,1},
{0,INF,0,0,0},
{0,2,INF,4,0},
{0,0,0,INF,0},
{0,0,0,1,INF}};
int startNode = 1;
dijkstra(W,verticies,startNode-1);
}
public static void dijkstra(int G[][],int n,int startnode)
{
int INF = Integer.MAX_VALUE, nINF = Integer.MIN_VALUE;
//int cost[MAX][MAX],distance[MAX],pred[MAX];
//int visited[MAX],count,mindistance,nextnode,i,j;
int cost[][] = new int[n][n];
int distance[] = new int[n];
int pred[] = new int[n];
boolean visited[] = new boolean[n];
int count=0, mindistance=0, nextnode=0,i,j;
//pred[] stores the predecessor of each node
//count gives the number of nodes seen so far
//create the cost matrix
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(G[i][j]==0)
cost[i][j]=INF;
else
cost[i][j]=G[i][j];
//initialize pred[],distance[] and visited[]
for(i=0;i<n;i++)
{
distance[i]=cost[startnode][i];
pred[i]=startnode;
visited[i]=false;
}
distance[startnode]=0;
visited[startnode]=true;
count=1;
while(count<n-1)
{
mindistance=INF;
//nextnode gives the node at minimum distance
for(i=0;i<n;i++)
if(distance[i]<mindistance&&!visited[i])
{
mindistance=distance[i];
nextnode=i;
}
//check if a better path exists through nextnode
visited[nextnode]=true;
for(i=0;i<n;i++)
if(!visited[i])
if(mindistance+cost[nextnode][i]<distance[i])
{
distance[i]=mindistance+cost[nextnode][i];
pred[i]=nextnode;
}
count++;
}
//print the path and distance of each node
for(i=0;i<n;i++)
if(i!=startnode)
{
if(distance[i] == INF || distance[i] < 0){
System.out.print("\nNo edge exists between node "+(startnode+1)+" and node "+(i+1));
} else {
System.out.format("\nDistance of node %d = %d", (i + 1), distance[i]);
System.out.format("\nPath = %d", (i + 1));
j = i;
do {
j = pred[j];
System.out.format("<-%d", (j + 1));
} while (j != startnode);
}
}
}
I don’t know exactly how, but you are somehow getting INF into your calculations. My suspicion goes to the line distance[i]=mindistance+cost[nextnode][i];, but it may not be the only culprit, I have not checked. When mindistance is 1 (or greater) and cost is Integer.MAX_VALUE, you get an arithmetic overflow and the result gets negative. Further behaviour, I have not predicted, but it’s not as expected.
When in the two places you define INF I change the value to 1,000,000, I get the following output from your program:
Distance of node 2 = 6
Path = 2<-3<-1
Distance of node 3 = 4
Path = 3<-1
Distance of node 4 = 2
Path = 4<-5<-1
Distance of node 5 = 1
Path = 5<-1
I believe this is correct.
The way I found out? I stuck this statement into the middle of your outer while loop:
System.out.println("count " + count + " nextnode " + nextnode + " mindistance " + mindistance);
When it printed a large negative number, I started suspecting an arithmetic overflow. Until you learn to use a debugger, System.out.println() is your friend for debugging.

write 0's and 1's on each line where the last 2 weren't the same

There's an error in the logic of what I've build at the moment.
What should be happening is that my code should display a grid of 0's and 1's.
Like so:
001001
101101
010110
110010
001101
So what has to happen here is that:
For each row there can't be more than 2 numbers of the same type consecutively
the numbers are picked randomly
for each column there can't be more than 2 numbers of the same type consecutively
there can be a maximum of 3 of each type of number going by column or row
edit: to further clarify
ok so I have a row like this:
0 1 0 1 1 0
- As you can see there will always be 3 x 1, and 3 x 0
- the order of numbers is picked randomly (so it might go 0 1, or 1 1, or 0 0 to start etc)
- there can never be more than 2 numbers of the same type consecutively, for instance if it's 001100, you can see that there were 2 0's, then it had to display a 1, but then there were 2 1's, so it had to display an 0. So 011100 couldn't happen (3 1's consecutively) or 000101 (3 0's consecutively)
Based upon this, but for now not essential, the same no 2 numbers consecutively must apply in columns (so in my successful example it goes 001001 across, there are at most 2 0's consecutively. But looking down you get 010101 (that is to say, once again, no more than 2 consecutively)
So my code is as follows:
import java.util.Random;
public class Main {
public static void main(String[] args) {
int l = 6;
int w = 6;
Random rd = new Random();
// Create a grid that is 6 x 6
int[][] grid = new int[l][w];
// for each row
for (int i = 0; i < l; i++) {
int zCount = 0;
int oCount = 0;
int current;
int lastA = 2;
int lastB = 2;
// for each item in the row
for (int j = 0; j < w; j++) {
// set the current item to either 0 or 1
current = rd.nextInt(2);
// make sure there aren't already (e.g. 3 items out of 6)
// items in the row
if (j % 2 == 1) {
// hold every second element
lastA = current;
} else {
// hold every first element
lastB = current;
}
if (current == 1) {
if (oCount != 3) {
if (lastA != lastB) {
// if the two previous items aren't the same
grid[i][j] = current;
// add to the counter
oCount++;
}
}
}
if (current == 0) {
if (zCount != 3) {
if (lastA != lastB) {
// if the two previous items aren't the same
grid[i][j] = current;
// add to the counter
zCount++;
}
}
}
System.out.print(grid[i][j]);
}
System.out.println(" ");
}
}
}
The problem is it generates as follows:
010010
100001
100010
000010
100001
001000
So obviously it doesn't conform to the first, third or fourth points.
I have absolutely no idea why! Except for the columns (third point) which I haven't initialised.
Can anybody work out what the logical failure is in my code?
Thanks for your help!
Here is my procedural solution which tries to keep the amount of required code as small as possible. It is capable of computing 2D-Arrays with arbitrary rows and columns like [6, 6] or [4, 7] or [3, 8] for example. The complexity of the algorithm is O(n) with n = rows * columns.
The program computes an arbitrary 2D-Array (grid) populated with either a 0 or 1. The grid guarantees the following characteristics, formulated mathematically:
∀ r,c ∈ Integer | 0 ≤ r < grid.rows, 0 ≤ c < grid.columns :
r - 2 ≥ 0 ⇒ cardinality( distinct( grid[r][c], grid[r-1][c], grid[r-2][c] )) = 2
r + 2 < grid.rows ⇒ cardinality( distinct( grid[r][c], grid[r+1][c], grid[r+2][c] )) = 2
c - 2 ≥ 0 ⇒ cardinality( distinct( grid[r][c], grid[r][c-1], grid[r][c-2] )) = 2
c + 2 < grid.columns ⇒ cardinality( distinct( grid[r][c], grid[r][c+1], grid[r][c+2] )) = 2
or in other words:
the grid does neither contain a row nor a column which has three or more consecutive 0's or 1's.
Below the Java code I will explain how the algorithm works and why it is designed as it is:
public static void main(String[] args) {
int[][] grid = anyGrid(8, 13);
}
private static int[][] anyGrid(int rows, int cols) {
int[][] grid = new int[rows][cols];
int row = 0;
for (int col = 0; col - row < cols; col++) {
for (int r = row; r >= 0 && col - r < cols;) {
setBit(grid, r, col - r--);
}
if (row < rows - 1) row++;
}
return grid;
}
private static void setBit(int[][] grid, int row, int col) {
int vInd = calcVerticalIndicator(grid, row, col);
int hInd = calcHorizontalIndicator(grid, row, col);
if (isPartiallyRestricted(vInd, hInd)) {
grid[row][col] = flip(vInd);
} else if (isFullyRestricted(vInd, hInd)) {
grid[row][col] = vInd;
grid[row - 1][col] = flip(vInd);
} else {
grid[row][col] = Math.abs(vInd) <= 1
? flip(vInd)
: Math.abs(hInd) <= 1 ? flip(hInd) : anyBit();
}
}
private static boolean isPartiallyRestricted(int vInd, int hInd) {
return vInd == hInd;
}
private static boolean isFullyRestricted(int vInd, int hInd) {
return vInd + hInd == 1;
}
private static int calcVerticalIndicator(int[][] grid, int row, int col) {
return calcIndicator(grid, row - 1, col, row - 2, col, 2);
}
private static int calcHorizontalIndicator(int[][] grid, int row, int col) {
return calcIndicator(grid, row, col - 1, row, col - 2, 4);
}
private static int calcIndicator(int[][] grid, int row1, int col1, int row2, int col2, int unrestricted) {
try {
return grid[row1][col1] * grid[row2][col2] + (grid[row1][col1] - grid[row2][col2]) * unrestricted;
} catch (IndexOutOfBoundsException e) {
return unrestricted;
}
}
private static int anyBit() {
return (int) (Math.random() * 2);
}
private static int flip(int bit) {
return bit == 0 ? 1 : 0;
}
The challenge we face is not to ensure that there are no three consecutive 0's or 1's in a row only or in a column only. The challenge is to ensure that no three consecutive 0's or 1's are neither in a row nor in a column by providing an efficient algorithm.
The tricky situation we may run into looks like this:
Let's consider the situation where all the cells at the top and to the left of the cell outlined in blue are already populated and do not violate the rules define above.
picture a) we want to populate the cell having a blue outline. The two cells at it's top are populated with two 0's while the cells at it's left are populated with two 1's. Which value should we choose? Due to symmetry it doesn't matter if we choose a 0 or a 1. Hence, let's go with a 0.
picture b) populating the cell outlined in blue with a 0 violates one rule defined above: the grid does not contain a column with three or more consecutive 0's or 1's. Hence we have to change the value of one of the two cells above of the blue cell.
picture c) say we change the value of the cell which is immediately above the blue cell, from 0 to 1. This could result in the violation of some rules, caused by the already populated cells to the left of the modified cell.
picture d) but a violation would mean that both cells to the left must have a value of 1.
picture e) this would imply that both cells to their top must have a value of 0 which is a contradiction to a situation we assumed. Therefore, changing the cell immediately at the top of the cell outlined in blue will not cause any violation of the rules.
To address the precondition, that no cells to the right of the modified cell are already populated, the algorithm populates the grid in a diagonal way. The population of cells occur in the order as shown below:
The final thing I like to explain is how the algorithm decides which values are available to choose from for each cell. For each cell it inspects the two top-most and two left-most cells and calculates an indication value. This value is used to determine the possible values for a cell by using arithmetic calculation as follows:
if the two cells inspected are both populated with 0's return an indicator value of 0.
if the two cells inspected are both populated with 1's return an indicator value of 1.
I have selected those two values because they communicate the fact, that this values are not permitted, in an intuitive way.
Then I selected a function to communicate if both, the column cells and the row cells, restrict the cell to populate by the same value. This is the case if both indicator values are equal. Keep this characteristic in mind, because we have to find values for the situation when no restriction applies from the column cells or the row cells.
If both indicators restrict the value to populate the cell with by a different value, the sum of them is 1. This is the second characteristic we have to keep in mind when searching for proper indicator values when no restriction applies.
The last thing the algorithm has to achieve is to find proper values when no restriction applies without compromising the unique indicators defined above.
Preserving the indication when the cell is restricted by the same value can be achieved by selecting values for the row and column indicators which are different from 0 and 1 and different from each other.
Preserving the indication when the cell is restricted by both values can be achieved by selecting values being greater than 1 and having a delta to each other of at least 2.
The algorithm does indicate no restriction for a row by the values 2 and -2 and for a column by the values 4 and -4. This values do not conflict with the operations used to identify the other two cases.
I hope this documentation helps to understand the whole program and how it does solve the problem statement. I am glad to hear your comments.
Many of the solutions given are extremely long and complicated. Here's a solution with very minimal code (Ideone Example here):
int row, col, n = 8;
int[][] grid = new int[n][n], cCount = new int[n][2], rCount = new int[n][2];
Deque<Entry<Integer,Integer>> freeInd = new ArrayDeque<Entry<Integer,Integer>>();
Random rand=new Random();
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
// Calcualte constraints: row, col = {-1, 0, 1}, -1 => no constraint.
row = j > 1 && grid[i][j-2] == grid[i][j-1] ? (grid[i][j-1] == 0 ? 1:0):
(rCount[i][0] >= n/2 ? 1: // too many 0's
(rCount[i][1] >= n/2 ? 0:-1)); // too many 1's
col = i > 1 && grid[i-2][j] == grid[i-1][j] ? (grid[i-1][j] == 0 ? 1:0):
(cCount[j][0] >= n/2 ? 1: // too many 0's
(cCount[j][1] >= n/2 ? 0:-1)); // too many 1's
grid[i][j] = row == -1 && col == -1 ? rand.nextInt(2):(row > -1 ? row:col);
// Handle Constraints
if( row == -1 && col == -1){ // no constraint
freeInd.push(new SimpleEntry<Integer,Integer>(i, j)); // add to free indices
} else if( (row > -1 && col > -1 && row != col) // constraint conflict
|| (row > -1 && rCount[i][row] >= n/2) // count conflict
|| (col > -1 && cCount[j][col] >= n/2)){ // count conflict
Entry<Integer, Integer> last = freeInd.pop(); // grab last free index
while(i > last.getKey() || j > last.getValue()){
j = (j-1+ n)%n; // step indices back
i = (j == n-1) ? i-1:i;
rCount[i][grid[i][j]]--; // reduce counters
cCount[j][grid[i][j]]--;
}
grid[i][j] = grid[i][j] == 0 ? 1:0; // flip value
}
rCount[i][grid[i][j]]++; // increment counters
cCount[j][grid[i][j]]++;
}
}
The idea here is that you walk along each row of the matrix adding 0's and 1's abiding by the following rules:
If the current index is unconstrained (i.e. it can be 0 or 1) we choose a value randomly.
If the current index is constrained we force it to have the constrained value.
If there are multiple constraints that do not agree, we revert back to the last unconstrained index (freeInd) by first incrementally stepping backwards along the rows of the matrix, decrementing the count for the given value (0 or 1). E.g. this is done for rows with rCount[i][grid[i][j]]--. When the unconstrained vertex is finally reached, flip it's value.
Finally, increment the count of the value (0 or 1) for the current row and column. E.g. this is done for rows with rCount[i][grid[i][j]]++
The 1st problem which i found in your solution is it's initializing the value of counter value (ocount and zcount) as zero and the only way grid(array) is assigned a value is when if it's greater than three, and the way i see if i am not mistaken the value of counter is incremented in the loop in which they are checked to be greater than 3, and that condition can never be reached .
To solve this problem use the algo of backtracking by assigning the new value to a different value if the calue
A working code in jsFiddle (for 6x6 grids):
$(function(){
function print(str){
$("body").append(str + "<br/>");
}
function toBin(num, length){
if(!length){
length = 3;
}
var str = num.toString(2);
while(str.length < length){
str = 0 + str;
}
return str;
}
var wrongAnds = [
parseInt('000000111', 2),
parseInt('000111000', 2),
parseInt('111000000', 2),
parseInt('100100100', 2),
parseInt('010010010', 2),
parseInt('001001001', 2),
];
var wrongOrs = [
parseInt('111111000', 2),
parseInt('111000111', 2),
parseInt('000111111', 2),
parseInt('011011011', 2),
parseInt('101101101', 2),
parseInt('110110110', 2),
];
function test(mask){
for (var i = 0; i < 6; i++) {
if((wrongAnds[i] & mask) == wrongAnds[i]){
return false;
}
if((wrongOrs[i] | mask) == wrongOrs[i]){
return false;
}
}
return true;
}
var threeGrid = [];
var toRight = [];
var toBottom = [];
for(var mask = 1<<9-1; mask >= 0; mask--){
if(test(mask)){
threeGrid.push(mask);
}
}
function numberOfSetBits(i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
function getCol(grid, col){
var ret = 0;
for(var i=0; i<3; i++){
ret += (grid & (1 << (i*3+col))) >> (i*2+col);
}
return ret;
}
var wrongAnds6 = [
parseInt('011100', 2),
parseInt('001110', 2)
];
var wrongOrs6 = [
parseInt('100011', 2),
parseInt('110001', 2)
];
for(var i = 0; i < threeGrid.length; i++){
for(var j = 0; j < threeGrid.length; j++){
var grid1 = threeGrid[i];
var grid2 = threeGrid[j];
var toRightOk = true;
var toBottomOk = true;
var printit = (i==0);
for(var k=0;k<3;k++){
var row = ((grid1 & wrongAnds[k]) << 3 >> (k*3)) + ((grid2 & wrongAnds[k]) >> (k*3));
var col = ((getCol(grid1, k)) << 3) + ((getCol(grid2, k)));
if(numberOfSetBits(row) != 3
|| ((wrongAnds6[0] & row) == wrongAnds6[0])
|| ((wrongAnds6[1] & row) == wrongAnds6[1])
|| ((wrongOrs6[0] | row) == wrongOrs6[0])
|| ((wrongOrs6[1] | row) == wrongOrs6[1])
) {
toRightOk = false;
}
if(numberOfSetBits(col) != 3
|| ((wrongAnds6[0] & col) == wrongAnds6[0])
|| ((wrongAnds6[1] & col) == wrongAnds6[1])
|| ((wrongOrs6[0] | col) == wrongOrs6[0])
|| ((wrongOrs6[1] | col) == wrongOrs6[1])
) {
toBottomOk = false;
}
}
if(toRightOk){
if(!toRight[grid1]){
toRight[grid1] = [];
}
toRight[grid1].push(grid2);
}
if(toBottomOk){
if(!toBottom[grid1]){
toBottom[grid1] = [];
}
toBottom[grid1].push(grid2);
}
}
}
function intersect(arr1, arr2){
var results = [];
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) !== -1) {
results.push(arr1[i]);
}
}
return results;
}
var found = false;
while(!found){
var grid1 = threeGrid[0];
var grid1 = threeGrid[Math.floor(Math.random()*threeGrid.length)];
var grid2 = toRight[grid1][Math.floor(Math.random()*toRight[grid1].length)];
var grid3 = toBottom[grid1][Math.floor(Math.random()*toBottom[grid1].length)];
var arr4 = intersect(toBottom[grid2], toRight[grid3]);
if(arr4.length > 0){
var grid4 = arr4[Math.floor(Math.random()*arr4.length)];
found = true;
}
}
function gridToStrings(grid){
var rowS = [];
for(var i=0; i<3; i++){
rowS.push(toBin(((grid & wrongAnds[i]) >> (i*3))));
}
return rowS;
}
var grid1S = gridToStrings(grid1);
var grid2S = gridToStrings(grid2);
var grid3S = gridToStrings(grid3);
var grid4S = gridToStrings(grid4);
print(grid1S[0] + grid2S[0]);
print(grid1S[1] + grid2S[1]);
print(grid1S[2] + grid2S[2]);
print(grid3S[0] + grid4S[0]);
print(grid3S[1] + grid4S[1]);
print(grid3S[2] + grid4S[2]);
});
Theory:
Find all possible 3x3 grids
Find all possible left-to-right and top-to-bottom pairings
get 4 random grids to form the 6x6 grid
Implementation:
Represent 3x3 grids as 9bit integers. A 3x3 grid is wrong if there are 3 1s or 3 0s in it. This can be easily filtered with a couple bitwise operations.
Test the Cartesian product of these 3x3 grids (Compare every grid with every grid). Check if there are exactly 3 0s and 3 1s in all rows and columns (put the second grid right to the first grid to check 3 rows, and put it below the first grid to check 3 columns), and that there are no consecutive 3 0s or 1s.
get the top-left, top-right and bottom-right grids. Check if there is an available 4th grid that can go below the top-right grid and right to the bottom-left grid. If there is none, restart step 4, otherwise pick one.
A couple outputs:
011010
100101
001011
110100
101100
010011
110010
101100
010011
001101
100110
011001
001101
110010
010011
101100
110100
001011
Edit:
there is only 1120 solutions to this problem (jsFiddle). There are 2^36 ways to fill a 6x6 grid with 0s and 1s. If you used brute force (get a random 6x6 grid, then check if its right), that would mean an average ~61356676 (6.1*10^7) executions to find a correct solution. Even thought your method is somewhat faster (it can fail sooner if its not the last digit thats wrong), it might still be slow.
I think there are two problems with your code:
If oCount or zCount have become 3 there are no more assignments grid[i][j]=current if the random value is not acceptable. You get zeroes at these positions (to which the grid was initialized).
Near the right bottom there might not be any more valid solutions. You would have to undo previous assignments, i.e. you would need to do some kind of backtracking.
I would recommend starting with a valid solution and transforming this solution step by step according to random values for grid positions - but only if this is possible without breaking validity. If have prepared an example implementation:
public static void main(String[] args) {
int l = 6, w = 6;
Grid g = new Grid(l, w);
Random rd = new Random();
// initialize with checkerboard pattern (which is a valid solution)
for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) g.arr[y][x] = (x ^ y) & 1;
// construct a valid grid by transformation of grids while preserving validity
for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) {
int v = rd.nextInt(2), v2 = v ^ 1;
if (g.arr[y][x] == v) continue;
// try to modify current grid by exchanging values: 01/10=>10/01 or 10/01=>01/10
// (keep parts of the grid which have already been adapted to random values)
rotating: for (int y2 = y + 1; y2 < l; y2++) for (int x2 = x; x2 < w; x2++) {
if (g.arr[y2][x] == v && g.arr[y][x2] == v && g.arr[y2][x2] == v2) {
g.rotate(x, y, x2, y2);
// keep result if grid is still valid, undo otherwise
if (g.rotatedOk(x, y, x2, y2)) break rotating;
g.rotate(x, y, x2, y2);
}
}
}
g.printOn(System.out);
}
public static class Grid {
int l, w;
int[][] arr;
Grid(int l, int w) {
this.arr = new int[this.l = l][this.w = w];
}
void rotate(int x, int y, int x2, int y2) {
int v;
v = arr[y][x]; arr[y][x] = arr[y2][x]; arr[y2][x] = v;
v = arr[y][x2]; arr[y][x2] = arr[y2][x2]; arr[y2][x2] = v;
}
boolean rotatedOk(int x, int y, int x2, int y2) { // check after rotation
return okAt(x, y) && okAt(x2, y) && okAt(x, y2) && okAt(x2, y2);
}
private boolean okAt(int x, int y) { // check single position in grid
int v = arr[y][x];
if (count(x, y, -1, 0, v) + count(x, y, 1, 0, v) > 1) return false;
if (count(x, y, 0, -1, v) + count(x, y, 0, 1, v) > 1) return false;
return true;
}
private int count(int x, int y, int dx, int dy, int v) {
for (int n = 0; ; n++) {
x += dx; y += dy;
if (x < 0 || x >= w || y < 0 || y >= l || arr[y][x] != v) return n;
}
}
void printOn(PrintStream s) {
for (int y = 0; y < l; y++) { for (int x = 0; x < w; x++) s.print(arr[y][x]); s.println(); }
}
}
The problem with your approach is that you need a mechanism that handles when a new value can't be used because it follows two similar values, but the other value can't be used because it is under two other values. For example, say your grid has got this far:
101010
011010
00?
You would then need to slowly roll back positions and try different values.
The following code solves that problem using recursion:
import java.util.Random;
public class Main {
final int height = 6;
final int width = 6;
int[][] grid;
Random rd = new Random();
public static void main(final String[] args) {
Main main = new Main();
main.process();
}
private void process() {
// Create a grid that is 6 x 6
grid = new int[height][width];
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
grid[x][y] = -1;
}
}
recurseFillMatrix(0, 0);
}
private boolean recurseFillMatrix(final int x, final int y) {
// first, try putting a random number in the cell
int attempt = 1;
grid[x][y] = Math.abs(rd.nextInt()%2);
do {
if(isGridValid()) {
if(x == (width - 1) && y == (height - 1)) {
printGrid();
return true;
}
boolean problemSolved;
if(x == (width - 1)) {
problemSolved = recurseFillMatrix(0, y + 1);
} else {
problemSolved = recurseFillMatrix(x + 1, y);
}
if(problemSolved) {
return true;
}
}
attempt++;
grid[x][y] = 1 - grid[x][y];
} while(attempt <= 2);
grid[x][y] = -1;
return false;
}
private boolean isGridValid() {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// if the current item is -1, then we are finished
if(grid[x][y] == -1) {
return true;
}
// if we are after the second column
if(x > 1) {
if(grid[x-2][y] == grid[x-1][y] && grid[x-1][y] == grid[x][y]) {
return false;
}
}
// if we are after the second row
if(y > 1) {
if(grid[x][y-2] == grid[x][y-1] && grid[x][y-1] == grid[x][y]) {
return false;
}
}
// total the values in this column
int total = 0;
for(int i = 0; i <= y; i++) {
total += grid[x][i];
}
if(y == (height - 1)) {
if(total != 3) {
return false;
}
} else {
if(total > 3) {
return false;
}
}
// total the values in this row
total = 0;
for(int i = 0; i <= x; i++) {
total += grid[i][y];
}
if(x == (width - 1)) {
if(total != 3) {
return false;
}
} else {
if(total > 3) {
return false;
}
}
}
}
return true;
}
private void printGrid() {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
System.out.print(grid[x][y]);
}
System.out.println("");
}
}
}
The isGridValid() method uses your defined rules to check if the grid (as it is filled so far) complies with the rules. At the first sign that it does not, it returns false.
If I have to change your solution to achieve the result, here is what it should look like..
Take the incrementors for oCount and zCount in a separate if-else
Take the assignment to grid(i,j) outside the loop
Your if-else block is not taking into account every condition possible, like
What about when last 2 items are same
What about when the zCount or oCount has reached 3
Taking into account these consideration, this code works fine.
import java.util.Random;
public class Main {
public static void main(String[] args) {
int l = 6;
int w = 6;
Random rd = new Random();
// Create a grid that is 6 x 6
int[][] grid = new int[l][w];
// for each row
for (int i = 0; i < l; i++) {
int zCount = 0;
int oCount = 0;
int current;
int lastA = 2;
int lastB = 2;
// for each item in the row
for (int j = 0; j < w; j++) {
// set the current item to either 0 or 1
current = rd.nextInt(2);
// make sure there aren't already (e.g. 3 items out of 6)
// items in the row
if (current == 1) {
if (oCount != 3) {
if (lastA == lastB) {
current = lastA == 1 ? 0 : 1;
}
} else {
current = current == 1 ? 0 : 1;
}
} else if (current == 0) {
if (zCount != 3) {
if (lastA == lastB) {
current = lastA == 1 ? 0 : 1;
}
} else {
current = current == 1 ? 0 : 1;
}
}
grid[i][j] = current;
if (current == 1) {
oCount++;
} else {
zCount++;
}
if (j % 2 == 1) {
// hold every second element
lastA = current;
} else {
// hold every first element
lastB = current;
}
System.out.print(grid[i][j]);
}
System.out.println(" ");
}
}
}
Again, This solution takes care of row conditions only. You would need to do similar checks for columns as well, to achieve the full result
HTH
here I tested you problem and seems that it is what you need.
I used a functional approach using Guava, it is quite simple, readable and has a short code.
#Test
public void test_permutations()
{
List<Integer> binary = Lists.newArrayList(1,0,1,0,1,0); // Domain list
Set<String> flattenSet = Sets.newHashSet(); // Store non-repetitive values
// Create list of possible values
Collection<List<Integer>> permutations = Collections2.permutations(binary);
for (List<Integer> permutation : permutations)
{
String joinString = StringUtils.join(permutation, "");
flattenSet.add(joinString);
}
// Create predicate to filter positive values
Predicate<String> predicate = new Predicate<String>() {
public boolean apply(String input) {
// Discard wrong values
if (input.contains("000") || input.contains("111")) {
return false;
} else {
return true;
}
}
};
// Use predicate to filter values
Collection<String> filteredList = Collections2.filter(flattenSet, predicate);
// Display result
for (String result : filteredList) {
System.out.println(result);
}
}
It is simple, I've commented the code to be clear but you can debug it to understand step by step.
The generated output is:
010011
110010
010101
010110
100110
101001
011010
110100
001011
001101
011001
101010
101100
100101
Hope to help
I think that its a mistake to think of generating it one element at at time. Instead imagine that I generate the entire set of permissible rows {001100,101010,....etc} There are only 6!/(3!3!)=20 ways to arrange three ones and three and some of them will be excluded. Now I am going to generate a game tree by saying that a move is selecting a valid row for the next row. If I discover at some point that there are no more valid moves then i will back track and try a different move.
To generate a move I randomly select a row, if its a valid move, I try to select another move, if that is impossible I backtrack, effectively doing a (random) depth first search of the game tree.
public class gametree {
public static ImmutableList<Row> allValidRows = // create a list of all valid rows.
public static List<Rows> getValidMoves(Move parent){ //Backtracks up the
//tree to the root to find the current state of the board, and returns
//which ever of allValidRows are valid given the game board.
}
public class Move {
public final Move parent;
public List<Rows> validMoves;
public final Row thisMove;
public int depth=0;
Move(Move parent, Row thisMove){
this.thisMove = thisMove;
this.parent = parent;
this.validMoves = getValidMoves(parent);
Move hold=parent;
while(hold!=null){
depth++; hold = parent.parent;
}
}
}
void run {
//pick first move
Move Root = new Move(null, Collections.Shuffle(allValidRows).get(0));
Move FinalMove = search(Root);
//Something to print out the answer here
}
public Move search(Move move){
if(depth==5){ return Move} //If I get to row six I win.
else if(move.validMoves.isEmpty()) { //If there are no valid moves,
//then this move wasnt valid, to strip it from the parent's
//possible moves and try again
move.parent.validMoves.remove(move.thisMove);
search(move.parent);
} else { //pick a random valid move and create a nextMove
Move nextMove = new Move(move, Collection.Shuffle(move.getValidMoves).get(0))
search(nextMove);
}
}
The worst case for this algorithm is that there is only one victory state and it has to try every possible state, but in practice this game does not seem very restrictive so it will probably not take long at all.
This code is strictly illustrative.

Categories