#include <stdio.h>
#include <stdlib.h>
#define NMAX 32
#define DEBUG 0

void copy(int n, int A[NMAX][NMAX], int B[NMAX][NMAX]);

void print_upper(int n, int A[NMAX][NMAX]);

void get_permuted_matrix(int n, int p[NMAX], int A[NMAX][NMAX], int p_A[NMAX][NMAX]);

void get_can_form(int level, int n, int A[NMAX][NMAX], int p_A[NMAX][NMAX],
    int can_A[NMAX][NMAX], int used[NMAX], int p[NMAX], int verbose);

int main(int argc, char *argv[])
{
    int n;
    int A[NMAX][NMAX];
    int p_A[NMAX][NMAX];
    int can_A[NMAX][NMAX];
    int used[NMAX];
    int p[NMAX];
    int n_graph;
    int verbose;
 
    if (argc!= 2)
    {
       printf("Usage: %s <verbose>\n", argv[0]);
       exit(0);
    }
    verbose= atoi(argv[1]);
    n_graph=0;

    while (read_upper(&n, A))
    {
         n_graph++;
         if (verbose)
         {
             printf("Input graph %3d:\n", n_graph);
             print_upper(n, A);
         }
         get_can_form(0, n, A, p_A, can_A, used, p, verbose);
         if (verbose)
         {
             printf("Canonical form for graph %3d\n", n_graph);
         }
         print_upper(n, can_A);
    }
    printf("Normal termination: %10d graphs\n", n_graph);
}
// This function computes a canonical form for a graph by considering
// all permutations of the vertices and choosing one that gives a
// lexicographically minimized upper triangular adjacency matrix.
void get_can_form(int level, int n, int A[NMAX][NMAX], int p_A[NMAX][NMAX],
        int can_A[NMAX][NMAX], int used[NMAX], int p[NMAX], int verbose)
{
    int i;
    int cmp;

    if (level ==0)
    {
        for (i=0; i < n; i++)
        {
            used[i]=0;
        }
        copy(n, A, can_A);
    }
    if (level == n)
    {
        get_permuted_matrix(n, p, A, p_A);
#if DEBUG
        printf("The matrix permuted by ");
        for (i=0; i < n; i++)
            printf("%1d ", p[i]);
	printf(" : ");
        print_upper(n, p_A);
#endif
        cmp= compare(n, p_A, can_A);
        if (cmp < 0)
        {
#if DEBUG
            printf("Smaller adjacency matrix:\n");
            printf("Before:");
            print_upper(n, can_A);
            printf("After :");
            print_upper(n, p_A);
#endif
            copy(n, p_A, can_A);
        }
        return;
    }

    for (i=0; i < n; i++)
    {
        if (! used[i])
        {
#if 0
	    printf("Level %2d: Set p[%2d]= %2d]\n", level, level, i);
#endif
            p[level]= i;
            used[i]= 1;
            get_can_form(level+1, n, A, p_A, can_A, used, p, verbose);
            used[i]= 0;
        }
    }
}    
void copy(int n, int A[NMAX][NMAX], int B[NMAX][NMAX])
{
    int i, j;

    for (i=0; i < n; i++)
    {
        for (j=0; j < n; j++)
        {
            B[i][j]= A[i][j];
        }
    }
}
void get_permuted_matrix(int n, int p[NMAX], int A[NMAX][NMAX], int p_A[NMAX][NMAX])
{
    int i, j;

    for (i=0; i < n; i++)
    {
        for (j=0; j < n; j++)
        {
              p_A[p[i]][p[j]]= A[i][j];
        }
    }
}
int compare(int n, int A[NMAX][NMAX], int B[NMAX][NMAX])
{
    int i, j;

    for (i=0; i < n; i++)
    {
        for (j=i+1; j < n; j++)
        {
            if (A[i][j] < B[i][j]) return(-1);
            if (A[i][j] > B[i][j]) return( 1);
        }
    }
    return(0);
}
int read_upper(int *n, int A[NMAX][NMAX])
{
   int i, j;

   if (scanf("%d", n)!=1) return(0);

   for (i=0; i < *n; i++)
   {
       A[i][i]=0;
       for (j= i+1; j < *n; j++)
       {
          if (scanf("%1d", &A[i][j])!=1) return(0);
          A[j][i]= A[i][j];
       }
   }
   return(1);
}
void print_upper(int n, int A[NMAX][NMAX])
{
   int i, j;

   printf("%3d ", n);
   for (i=0; i < n; i++)
       for (j=i+1; j< n; j++)
           printf("%1d", A[i][j]);
   printf("\n");
}


