Search code examples
javaalgorithmrecursionbacktrackingrecursive-backtracking

Four Color Map Theorem Recursive Backtracking Algorithm


I have coded to following program to implement the Four Color Map Theorem (any map can be colored with only 4 colors without any adjacent regions being the same color, in a nutshell) recursively. Everything compiles, but my output gives me erroneous data (-1 for each region's color instead of a value 0-3 for now). My biggest question is why the output is incorrect.

For those wondering, the input file is an adjacency matrix which looks something as follows:

0 1 0 1  
1 0 1 0  
0 1 0 1  
1 0 1 0  

Here is my code:

public class FourColorMapThm 
{
    public static boolean acceptable(int[] map, int[][] matrix, int r, int c)
    {
        for(int i = 0; i < map.length; i++)
        {
            if(matrix[r][i] == 1)
            {
                if(map[i] == c) return false;
            }
        }
        return true;
    }

    public static boolean colorTheMap(int[] map, int[][] matrix, int r, int c)
    {
        boolean q = false;
        int i = 0;

        if(!acceptable(map, matrix, r, i)) return false;

        map[r] = i;
        boolean done = true;

        for(int j = 0; j < map.length; j++)
        {
            if(map[j] == -1)
            {
                done = false;
            }
        }
        if(done) return true;

        do
        {
            i++;
            q = colorTheMap(map, matrix, r+1, i);
            if(q) return true;
        }
        while(i <= 3);

        map[r] = -1;
        return false;
    }

    public static void main(String[] args) throws IOException
    {
        Scanner in = new Scanner(System.in);
        String snumRegions, fileName;
        int numRegions;

        System.out.print("Enter the number of regions: ");
        snumRegions = in.nextLine();
        numRegions = Integer.parseInt(snumRegions);

        System.out.print("\nEnter filename for adjacency matrix: ");
        fileName = in.nextLine();
        in.close();

        Scanner inFile = new Scanner(new FileReader(fileName));
        PrintWriter outFile = new PrintWriter("coloredMap.txt");
        int[][] matrix = new int[numRegions][numRegions];
        int[] map = new int[numRegions];

        //initializing matrix from file
        for(int row = 0; row < matrix.length; row++)
        {
            for(int col = 0; col < matrix.length; col++)
            {
                matrix[row][col] = inFile.nextInt();
            }
        }
        inFile.close();

        //initialize map vals to -1
        for(int i = 0; i < map.length; i++)
        {
                map[i] = -1;
        }

        colorTheMap(map, matrix, 0, 0);

        outFile.println("Region\t\tColor");
        for(int i = 0; i < map.length; i++)
        {
            outFile.println(i+1 + "\t\t" + map[i]);
        }
        outFile.close();
    }
}

Solution

  • You are not using c in colorTheMap, and you probably wanted to.

    The reason you're getting a map with all entries -1 is this:

        int i = 0;
        if(!acceptable(map, matrix, r, i)) return false;
        map[r] = i;
        .
        .
        .
        do
        {
            i++;
            q = colorTheMap(map, matrix, r+1, i);
            if(q) return true;
        }
        while(i <= 3);
        map[r] = -1;
    

    Every call of colorTheMap(map, matrix, r+1, i) returns false the moment it hits

        int i = 0;
        if(!acceptable(map, matrix, r, i)) return false;
    

    if any of its neighbors was already colored with 0 (since you are never using c, you will always assign 0 to map[r] in map[r] = i; if you reach that line), and so after the return, we immediately return false before assigning any color to r. I assume your input graphs are connected, and so any call of colorTheMap(map, matrix, r, c) either finds a neighbor of r colored with 0 and doesn't even set map[r] to anything else since if(!acceptable(map, matrix, r, i)) return false; will return immediately, or it only receives assignments of q = false in

        do
        {
            i++;
            q = colorTheMap(map, matrix, r+1, i);
            if(q) return true;
        }
        while(i <= 3);
    

    and undoes the coloring in the line map[r] = -1; that follows the loop.


    Another note: I assume you were trying to implement greedy coloring, but that is not optimal, i.e. you may end up with uncolored regions this way. The four color problem is way more intricate than a simple "just color everything with a color none of its neighbors was assigned and you're good", otherwise it wouldn't have taken more than a century for a proof that four colors suffice to show up. Here is what looks like an outline of a correct algorithm that takes quadratic time (citation in case the link gets lost: Neil Robertson, Daniel P. Sanders, Paul Seymour, and Robin Thomas. 1996. Efficiently four-coloring planar graphs. In Proceedings of the twenty-eighth annual ACM symposium on Theory of Computing (STOC '96). Association for Computing Machinery, New York, NY, USA, 571–575. DOI:https://doi.org/10.1145/237814.238005). It appeared another 20 years after the proof that four coloring planar graphs is always possible.