class Graphe {

    int nb ;            // Nombre de sommets
    Liste[] listeSucc ; // Listes d'adjacence
    String[] mot ;
    boolean[] dejaVu ; // Pour le parcours en profondeur.
    int[] pere ; // Arborescence de tremeaux
    int[] num ; // Ordre de visite
    int numCourant ;

    Graphe (String[] lesMots) { // Construit un graphe sans ar^etes
	nb = lesMots.length ;
	mot = lesMots ;
	listeSucc = new Liste [nb] ;
	for (int i=0 ; i<nb ; ++i)
	    listeSucc [i] = null ; // Pas de voisin pour l'instant
	dejaVu = new boolean [nb] ;
	pere = new int [nb] ;
	num = new int [nb] ;
    }

    static void afficher (Graphe g) {
	System.out.println ("digraph dico {") ;
	System.out.println ("  node [style=filled, fontcolor=red];") ;
	System.out.println ("  edge [style=bold, color=blue];") ;
	for (int i=0 ; i<g.nb ; ++i) {
	    //System.out.print ("  " + g.mot [i] + " -> { ") ;
	    //afficherSuccesseurs (g, i) ;
	    //System.out.println ("}") ;
	    //   Affichons ar^ete par ar^ete pour visualiser le cycle
	    System.out.println ("  " + g.mot [i] + " [label=\"" + g.mot[i] + " " + g.num[i] + "\"] ;") ; // Signalons le sommet
	    afficherAretes (g, i) ;
	    System.out.println () ;
	}
	System.out.println ("}") ;
    }

    static void afficherAretes (Graphe g, int i) {
	for (Liste v=g.listeSucc [i] ; v!=null ; v=v.suivant) {
	    System.out.print ("  " + g.mot[i] + " -> " + g.mot [v.contenu]) ;
	    //if (g.num[v.contenu] < g.num[i])
	    //	System.out.print (" [color=pink]") ; // Ar^ete retour
	    if (g.pere[v.contenu] == i)
		System.out.print (" [color=black]") ; // Ar^ete de tr'emeaux
	    System.out.println (" ;") ;
	}
    }
  
    static void afficherSuccesseurs (Graphe g, int i) {
	for (Liste v=g.listeSucc [i] ; v!=null ; v=v.suivant)
	    System.out.print (g.mot [v.contenu] + " ") ;
    }
  
    static void lettreQuiSaute (Graphe g) {
	for (int i=0 ; i<g.nb ; ++i)
	    for (int j=0 ; j<g.nb ; ++j)
		if (diffUneLettre (g.mot[i], g.mot[j]))
		    ajouterArete (g, i, j) ;
    }

    static void ajouterArete (Graphe g, int s, int d) { // graphe symmetrique
	g.listeSucc [s] = new Liste (d, g.listeSucc [s]) ;
	//g.listeSucc [d] = new Liste (s, g.listeSucc [d]) ;
    }

    static boolean diffUneLettre (String a, String b) { 
	// a et b supposes de meme longueur
	int i=0 ;
	while (i<a.length () && a.charAt (i) == b.charAt (i)) 
	    ++i ;
	if (i == a.length ())
	    return false ;
	if (a.charAt (i) > b.charAt (i))
	//if (a.charAt (i) < b.charAt (i)) // graphe inverse pour le tri topologique
	    return false ; // version orient'ee
	++i ;
	while (i<a.length () && a.charAt (i) == b.charAt (i)) 
	    ++i ;
	return i == a.length () ;
    }

    static void dfs (Graphe g, int x, int pere) {
	g.dejaVu[x] = true ;
	g.num[x] = g.numCourant++ ;
	g.pere[x] = pere ;
	//System.err.println (g.mot[x] + " " + x + " "  + g.num[x] + " " + g.pere[x]) ;
	for (Liste ls = g.listeSucc[x] ; ls != null ; ls = ls.suivant) {
	    int y = ls.contenu ;
	    if (!g.dejaVu[y]) {
		dfs (g, y, x) ;
	    }
	}
    }

    static void initVisit (Graphe g) {
	for (int x = 0 ; x < g.nb ; ++x) {  
	    g.dejaVu[x] = false ;
	    g.num[x] = -1 ;
	    g.pere[x] = -1 ;
	}
	g.numCourant = 0 ;
    }

    static void visit (Graphe g) {
	initVisit (g) ;
	for (int x = 0 ; x < g.nb ; ++x)
	    if (! g.dejaVu[x]) {
		dfs(g, x, -1) ;
	    }
    }


    public static void main (String[] args) {
	String[] dico3court = { "gag", "gai", "gaz", "gel", "gks", "gin", "gnu", "glu", "gui", "guy", "gre", "gue", "ace", "acm", "agi", "ait", "aie", "ail", "air", "and", "alu", "ami", "arc", "are", "art", "apr", "avr", "sur", "mat", "mur" } ;
	Graphe g = new Graphe (dico3court) ;
	//Graphe g = new Graphe (Dicos.dico4) ;
	lettreQuiSaute (g) ;
	g.listeSucc[9] = new Liste (22, g.listeSucc[9]) ;
	visit (g) ;
	afficher (g) ;
    }
}
