A Graph Generation Package

这是一个用于生成各种类型随机图的程序,包括随机图、随机连通图、随机有向无环图等。用户可以根据需求指定图的大小和特性,如顶点数、边数、是否加权等。
http://condor.depaul.edu/rjohnson/source/graph_ge.c
 
 
/*               A Graph Generation Package
            Richard Johnsonbaugh and Martin Kalin
   Department of Computer Science and Information Systems
                      DePaul University
                     Chicago, IL  60604
          johnsonbaugh@cs.depaul.edu, kalin@cs.depaul.edu

     This program generates graphs of specified  sizes  and
properties. Among the types of graphs are

     * random graphs
     * random connected graphs
     * random directed acyclic graphs
     * random complete weighted graphs
     * random pairs of isomorphic regular graphs
     * random graphs with Hamiltonian cycles
     * random networks

Graphs  may be specified further with respect to one or more
of these properties:

     * weighted or unweighted
     * directed or undirected
     * simple or nonsimple

We donate the program freely and hope others find it useful. We only
request attribution whenever this program is (successfully) shared. In
the spirit of the million dollar commercial vendors, we assume absolutely
no responsibility whatsoever for whatever mayhem this program
may inflict on your own system. Good luck!

     The program is menu-driven. The top-level menu is

     0. Exit Program
     1. Random Graph
     2. Random Digraph
     3. Random Connected Graph
     4. Random DAG (Directed Acyclic Graph)
     5. Random Complete Weighted Graph
     6. Random Isomorphic Graph Pair
     7. Random Hamiltonian Cycle Graph
     8. Random Network
     Choice?

Selecting  any  choice  except  0  brings  a  sub-menu.  For
example,  if  the  user  selects  1,  a  series  of  prompts
results:

          Number of Vertices:

          Number of Edges:

          1. Not Simple
          2. Simple
          Choice?

          1. Unweighted Edges
          2. Weighted Edges
          Choice?

          File for graph:

A  nonsimple  graph  is  allowed  to  contain parallel edges
and/or  loops.  If  the  user  selects  the  Weighted  Edges
option, the prompt

     Maximum Edge Weight:

allows  the  user  to  enter a maximum edge weight. A random
graph  meeting  the  chosen specifications is then generated
and  written to the file named by the user. Output takes the
form

n     m
v1    w1    c1
v2    w2    c2
      .
      .
      .

where  n  is  the  number of vertices and m is the number of
edges  in  the  graph. Edge i is incident on vertices vi and
wi.  The weight of edge i is ci. If the graph is unweighted,
the value of ci is 1 for all i.

     Other  options work similarly. For example, if the user
selects 2, Random Digraph, an output line

     vi    wi    ci

denotes  an  edge  directed  from  vi  to wi with weight ci.
Random  graphs  and digraphs are useful as input to programs
that  find components, that test for connectedness, and that
find   spanning   forests. Programs  that  find
spanning  trees  or minimal spanning trees can use
as  input  random  connected graphs, provided as option 3 on
the  top-level  menu.  Option 3 allows the user to designate
the connected graph's edges as weighted or unweighted.

     Directed  acyclic graphs, suitable as input to programs
that  find  topological orderings, are provided by
option  4  in  the  top-level  menu.  The program writes the
generated  graph to one file and and a topological sort to a
second  file.  The  user  may specify the number of vertices
and  edges,  the  maximum  weight per edge, and the two file
names.

     Complete   weighted  graphs  are  useful  as  input  to
programs   that   either   solve   exactly   the   traveling
salesperson  problem  or  approximate  an  exact solution to
this  problem. Option  5 generates such graphs,
allowing  the  user  to  specify  the  number  of  vertices,
whether  the graph is directed, the maximum weight per edge,
and the file name.

     Pairs  of  isomorphic  graphs,  suitable  as  input  to
programs  that  test  for  graph  isomorphism, are
provided  by  option  6  in  the top-level menu. The program
writes  two  isomorphic,  regular,  undirected graphs (i.e.,
isomorphic,  undirected  graphs in which all of the vertices
have   the   same   degree)  to  two  files  and  writes  an
isomorphism  to  a  third  file. Pairs of isomorphic regular
graphs  make  challenging  input  to  programs that test for
graph  isomorphism. Under this
option,  the  user  specifies  the  number  of vertices, the
common vertex degree, and the file names.

     Graphs  with  Hamiltonian cycles are useful as input to
programs  that  find  such  cycles or determine that they do
not  exist. Option  7  on  the  top-level  menu
provides  graphs with Hamiltonian cycles. The program writes
the  graph  to  one  file and a Hamiltonian cycle to another
file.  The  user may choose the number of vertices and edges
as well as the file names for the graph and the cycle.

     Networks,  provided  as option 8 on the top-level menu,
are  suitable  as  input to programs that find maximal flows.
Under  this  option,  the program generates a
simple, weighted, directed graph satisfying the following:

(a)  Vertex 1 has no incoming edges.

(b)  Vertex  n,  where n is equal to the number of vertices,
     has no outgoing edges.

The  user  selects  the  number  of  vertices and edges, the
maximum weight per edge, and the file name.

     This program does some error and integrity checking. As
examples,  the  user  may  not  specify  a  graph  with zero
vertices  or  edges.  If  a  simple, undirected graph with n
vertices  is  to  be  generated,  the user should specify at
most  n(n - 1)/2  edges. If a Hamiltonian cycle graph with n
vertices  is  to  be  generated,  the user should specify at
least  n  edges.  If  a  network  with  n  vertices is to be
generated,  the  user  should  specify  at  most n*n - 3n + 3
edges.  The program corrects erroneous user input wherever
feasible.  In the examples just cited, the program would set
the edge count correctly if the user did not.

   For a full discussion, see the article by Johnsonbaugh
and Kalin, "A Graph Generation Software Package,"
in Proceedings of the 22nd SIGCSE Technical Symposium.
*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>

/*** record for qsorting a graph to provide another isomorphic to it ***/
#define RecordSize 24
typedef struct {
   char record[ RecordSize ];
} Record;

int zero_vertex_or_edge_count( void );
void fix_imbalanced_graph( void );
void print_graph( int v,
                  int e,
                  char* out_file,
                  int* adj_matrix,
                  int dir_flag );
int unpicked_vertices_p( int* closed, int n );
int pick_to( int* closed, int vertices );
void network_flow_graph( int vertices,
                         int edges,
                         int max_weight,
                         char* outfile );
void hamiltonian_cycle_graph( int v,
                              int e,
                              int dir_flag,
                              char* out_file,
                              char* ham_file );
void complete_graph( int v,
                     int max_wgt,
                     int dir_flag,
                     char* out_file );
void directed_acyclic_graph( int v,
                             int e,
                             int max_wgt,
                             int weight_flag,
                             char* out_file,
                             char* dag_file );
void random_digraph( int v,
                     int e,
                     int max_wgt,
                     int weight_flag,
                     int simple_flag,
                     char* out_file );
void r_graph( int v,
              int e,
              int max_wgt, int weight_flag,
              char* out_file );
void random_graph( int v,
                   int e,
                   int max_wgt,
                   int weight_flag,
                   int simple_flag,
                   char* out_file );
void random_connected_graph( int v,
                             int e,
                             int max_wgt,
                             int weight_flag,
                             char* out_file );
void rename_edges( Record* ptr, int* aliases, int count );
void rename_vertices( int* aliases, int count );
int compare_strings( const void* a, const void* b );
void isomorphic_graph_pair( int vertices,
                            int spec_degree,
                            char* first,
                            char* second,
                            char* third );
void warning( char* message );
int bogus_file_name( int count );
void build_graphs( void );
void build_next_graph( void );
void display_main_menu( void );
void process_choice( void );
void display_simple_or_not_menu( void );
void display_dimensions_menu( int which );
void display_weighted_menu( void );
void display_max_weight_menu( void );
void display_directed_menu( void );
void display_max_degree_menu( void );
void display_outfile_menu( int count, int index1, int index2 );
void seed_ran( void );
int illegal_parms( int files );
int ran( int k );     /* customized random number generator */
void permute( int* a, int n ); /* gives a random permutation */

/* initialize array a so that a[ i ] = i */
void init_array( int* a, int end );

void swap( int* a, int *b ); /* swap two ints */
int get_int( char* indent ); /* get user input & check for valid input */
/*** miscellany ***/
#define True         1
#define False        0
#define None         -999
#define Undirected   0
#define Directed     1
#define ExitProgram  0

/*** graph generators ***/
#define RandomGraph            1
#define RandomDigraph          2
#define RandomConnectedGraph   3
#define DirectedAcyclicGraph   4
#define CompleteGraph          5
#define IsomorphicGraphPair    6
#define HamiltonianCycleGraph  7
#define NetworkFlowGraph       8

/*** warnings ***/
#define IllegalDimensions   "\n\n\tNeither edge nor vertex count may be zero.\n\n"
#define IllegalFileName     "\n\n\tOutput file has illegal name.\n\n"
#define InsufficientStorage "\n\n\tThere is not enough space for this size graph.\n\n"
#define SingleVertexNetwork "\n\n\tA single vertex network is not allowed.\n\n"

/*** prompts ***/
#define ToplevelPrompts  9
static char  *toplevel_prompts[] =
   { " 0. Exit Program ",
     " 1. Random Graph ",
     " 2. Random Digraph ",
     " 3. Random Connected Graph ",
     " 4. Random DAG (Directed Acyclic Graph) ",
     " 5. Random Complete Weighted Graph ",
     " 6. Random Isomorphic Graph Pair ",
     " 7. Random Hamiltonian Cycle Graph ",
     " 8. Random Network "
   };

#define SimpleGraphAns  1
#define SimpleOrNotPrompts  2
static char *simple_or_not_prompts[] =
   { " 1. Simple ",
     " 2. Not Simple "
   };

#define WeightedAns  2
#define WeightedOrNotPrompts  2
static char *weighted_or_not_prompts[] =
   { " 1. Unweighted Edges ",
     " 2. Weighted Edges "
   };

#define EdgeIndex         0
#define VertexIndex       1
#define VerticesOnly      -111
#define EdgesAndVertices  -222
static char *dimension_prompts[] =
   { " Number of Edges:    ",
     " Number of Vertices: "
   };

#define DirectedGraphAns 1
#define DirectedPrompts 2
static char *directed_prompts[] =
   { " 1. Directed Graph ",
     " 2. Undirected Graph "
   };

static char *degree_prompt =  " Degree Per Edge:  ";

#define ConnectedAns  1
#define ConnectedPrompts  2
static char *connected_prompts[] =
   { " 1. Connected Graph ",
     " 2. Unconnected Graph "
   };

static char *main_file_prompt = " File for graph:  ";

#define TopologicalSort      0
#define IsomorphicGraph      1
#define Isomorphism          2
#define HamiltonianCycle     3
static char *file_prompts[] =
   { " File for topological sort:  ",
     " File for isomorphic graph:  ",
     " File for isomorphism:  ",
     " File for Hamiltonian cycle:  "
   };


/*** output files ***/
#define MaxFileName   128
typedef struct out_files {
   char  outfile1[ MaxFileName + 1 ];
   char  outfile2[ MaxFileName + 1 ];
   char  outfile3[ MaxFileName + 1 ];
} Outfile;

/*** graphs ***/
typedef struct graph_parms {
   int      edge_count;
   int      vertex_count;
   int      max_weight;
   int      max_degree;
} GraphParms;

typedef struct graph_props {
   int      simple_p;
   int      weighted_p;
   int      directed_p;
   int      dag_p;
   int      isomorphic_p;
   int      network_p;
} GraphProps;

/*** menu ***/
typedef struct menu {
   GraphProps   props;
   GraphParms   parms;
   Outfile      outfiles;
} MenuStruct;

typedef MenuStruct *Menu;

static MenuStruct  menu_structure;
static Menu        menu = &menu_structure;

static int   build_more_graphs,
             menu_choice;

/* min, max, odd */
#undef min
#define min( x, y )   ((( x ) < ( y )) ? ( x ) : ( y ))

#undef max
#define max( x, y )   ((( x ) > ( y )) ? ( x ) : ( y ))

#define odd( num )    ( ( num ) % 2 )


int main()
{
   build_more_graphs = True;
   build_graphs();
   return 0;
}

void build_graphs( void )
{
   while ( build_more_graphs )
      build_next_graph();
}

void build_next_graph( void )
{
   display_main_menu();
   process_choice();
}


#define ChoicePrompt  " Choice? "
void display_main_menu( void )
{
   int  i;

   printf( "\n\n" );
   for ( i = 0; i < ToplevelPrompts; i++ )
      printf( "\n\t%s", toplevel_prompts[ i ] );
   printf( "\n\t" );
   printf( ChoicePrompt ); menu_choice = get_int( "\n\t" );
}

void process_choice( void )
{

   seed_ran();  /* seed system's random number generator */

   menu -> props.weighted_p =
      menu -> props.dag_p =
         menu -> props.isomorphic_p =
            menu -> props.simple_p =
               menu -> props.directed_p =
                  menu -> props.network_p = False;

   switch ( menu_choice ) {
      case ExitProgram:
         build_more_graphs = False;
         return;
      case RandomGraph:
         display_dimensions_menu( EdgesAndVertices );
         display_simple_or_not_menu();
         display_weighted_menu();
         if ( menu -> props.weighted_p )
            display_max_weight_menu();
         display_outfile_menu( 1, None, None );
         if ( illegal_parms( 1 ) )
            return;
         else
            random_graph( menu -> parms.vertex_count,
                          menu -> parms.edge_count,
                          menu -> parms.max_weight,
                          menu -> props.weighted_p,
                          menu -> props.simple_p,
                          menu -> outfiles.outfile1 );
      break;
      case RandomDigraph:
         menu -> props.directed_p = True;
         display_dimensions_menu( EdgesAndVertices );
         display_simple_or_not_menu();
         display_weighted_menu();
         if ( menu -> props.weighted_p )
            display_max_weight_menu();
         display_outfile_menu( 1, None, None );
         if ( illegal_parms( 1 ) )
            return;
         else
            random_digraph( menu -> parms.vertex_count,
                            menu -> parms.edge_count,
                            menu -> parms.max_weight,
                            menu -> props.weighted_p,
                            menu -> props.simple_p,
                            menu -> outfiles.outfile1 );
      break;
      case RandomConnectedGraph:
         menu -> props.simple_p = True;
         display_dimensions_menu( EdgesAndVertices );
         display_weighted_menu();
         if ( menu -> props.weighted_p )
            display_max_weight_menu();
         display_outfile_menu( 1, None, None );
         if ( illegal_parms( 1 ) )
            return;
         else
            random_connected_graph( menu -> parms.vertex_count,
                                    menu -> parms.edge_count,
                                    menu -> parms.max_weight,
                                    menu -> props.weighted_p,
                                    menu -> outfiles.outfile1 );
      break;
      case DirectedAcyclicGraph:
         menu -> props.dag_p = True;
         display_dimensions_menu( EdgesAndVertices );
         display_weighted_menu();
         if ( menu -> props.weighted_p )
            display_max_weight_menu();
         display_outfile_menu( 2, TopologicalSort, None );
         if ( illegal_parms( 2 ) )
            return;
         else
            directed_acyclic_graph( menu -> parms.vertex_count,
                                    menu -> parms.edge_count,
                                    menu -> parms.max_weight,
                                    menu -> props.weighted_p,
                                    menu -> outfiles.outfile1,
                                    menu -> outfiles.outfile2 );
      break;
      case CompleteGraph:
         display_dimensions_menu( VerticesOnly );
         display_max_weight_menu();
         display_directed_menu();
         display_outfile_menu( 1, None, None );
         complete_graph( menu -> parms.vertex_count,
                         menu -> parms.max_weight,
                         menu -> props.directed_p,
                         menu -> outfiles.outfile1 );
      break;
      case IsomorphicGraphPair:
         menu -> props.isomorphic_p = True;
         display_dimensions_menu( VerticesOnly );
         display_max_degree_menu();
         display_outfile_menu( 3, IsomorphicGraph, Isomorphism );
         if ( illegal_parms( 3 ) )
            return;
         else
            isomorphic_graph_pair( menu -> parms.vertex_count,
                                   menu -> parms.max_degree,
                                   menu -> outfiles.outfile1,
                                   menu -> outfiles.outfile2,
                                   menu -> outfiles.outfile3 );
      break;
      case HamiltonianCycleGraph:
         menu -> props.simple_p = True;
         display_dimensions_menu( EdgesAndVertices );
         display_directed_menu();
         display_outfile_menu( 2, HamiltonianCycle, None );
         if ( illegal_parms( 2 ) )
            return;
         else
            hamiltonian_cycle_graph( menu -> parms.vertex_count,
                                     menu -> parms.edge_count,
                                     menu -> props.directed_p,
                                     menu -> outfiles.outfile1,
                                     menu -> outfiles.outfile2 );
      break;
      case NetworkFlowGraph:
         menu -> props.network_p = True;
         menu -> props.directed_p = True;
         display_dimensions_menu( EdgesAndVertices );
         display_max_weight_menu();
         display_outfile_menu( 1, None, None );
         if ( illegal_parms( 1 ) )
            return;
         else
            network_flow_graph( menu -> parms.vertex_count,
                                menu -> parms.edge_count,
                                menu -> parms.max_weight,
                                menu -> outfiles.outfile1 );
      break;
   }
}

void display_simple_or_not_menu( void )
{
   int i;

   for ( i = 0; i < SimpleOrNotPrompts; i++ )
      printf( "\n\t\t%s", simple_or_not_prompts[ i ] );
   printf( "\n\t\t" );
   printf( ChoicePrompt );
   if ( get_int( "\n\t\t" ) == SimpleGraphAns )
      menu -> props.simple_p = True;
   else
      menu -> props.simple_p = False;
}

void display_directed_menu( void )
{
   int i;

   for ( i = 0; i < DirectedPrompts; i++ )
      printf( "\n\t\t%s", directed_prompts[ i ] );
   printf( "\n\t\t" );
   printf( ChoicePrompt );
   if ( get_int( "\n\t\t" ) == DirectedGraphAns )
      menu -> props.directed_p = True;
   else
      menu -> props.directed_p = False;
}

void display_dimensions_menu( int which )
{
   printf( "\n\t\t%s", dimension_prompts[ VertexIndex ] );
   menu -> parms.vertex_count = get_int( "\n\t\t" );
   if ( which == EdgesAndVertices ) {
      printf( "\t\t%s", dimension_prompts[ EdgeIndex ] );
      menu -> parms.edge_count = get_int( "\n\t\t" );
   }
}

void display_max_degree_menu( void )
{
   int  degree;

   printf( "\n\t\t%s", degree_prompt );
   degree = get_int( "\n\t\t" );
   menu -> parms.max_degree = degree;
   menu -> parms.edge_count = 1;       /* to avoid error message */
}

#define DefaultMaxWeight 1
void display_weighted_menu( void )
{
   int  i;

   for ( i = 0; i < WeightedOrNotPrompts; i++ )
      printf( "\n\t\t%s", weighted_or_not_prompts[ i ] );
   printf( "\n\t\t" );
   printf( ChoicePrompt );
   if ( get_int( "\n\t\t" ) == WeightedAns )
      menu -> props.weighted_p = True;
   else {
      menu -> props.weighted_p = False;
      menu -> parms.max_weight = DefaultMaxWeight;
   }
}

void display_max_weight_menu( void )
{
   printf( "\n\t\t\tMaximum Edge Weight:  " );
   menu -> parms.max_weight = get_int( "\n\t\t\t" );
}

void display_outfile_menu( int count, int index1, int index2 )
{
   int  i;

   for ( i = 0; i < count; i++ ) {
      if ( i == 0 ) {
         printf( "\n\t\t%s", main_file_prompt );
         scanf( "%s", menu -> outfiles.outfile1 );
      }
      else if ( i == 1 ) {
         printf( "\n\t\t%s", file_prompts[ index1 ] );
         scanf( "%s", menu -> outfiles.outfile2 );
      }
      else {
         printf( "\n\t\t%s", file_prompts[ index2 ] );
         scanf( "%s", menu -> outfiles.outfile3 );
      }
   }
}

int zero_vertex_or_edge_count( void )
{
   return ( menu -> parms.vertex_count == 0  ||
            menu -> parms.edge_count == 0 );
}

int bogus_file_name( int count )
{
   if ( count == 1 )
      return ( !strlen( menu -> outfiles.outfile1 ) );
   else
      return ( !strlen( menu -> outfiles.outfile1 ) &&
               !strlen( menu -> outfiles.outfile2 ) );
}

void fix_imbalanced_graph( void )
{
   int  max_edges;

   if ( menu -> props.simple_p ) {
      max_edges = menu -> parms.vertex_count
                  * ( menu -> parms.vertex_count - 1 );
      if ( !menu -> props.directed_p )
         max_edges /= 2;
      if ( menu -> parms.edge_count > max_edges )
         menu -> parms.edge_count = max_edges;
   }
   else if ( menu -> props.dag_p ) {
      max_edges = ( menu -> parms.vertex_count
                  * ( menu -> parms.vertex_count - 1 ) ) / 2;
      if ( menu -> parms.edge_count > max_edges )
         menu -> parms.edge_count = max_edges;
   }
   else if ( menu -> props.isomorphic_p ) {
      if ( odd( menu -> parms.max_degree ) )
         if ( odd( menu -> parms.vertex_count ) )
            menu -> parms.vertex_count++;
         if ( menu -> parms.vertex_count <= menu -> parms.max_degree )
            menu -> parms.vertex_count = menu -> parms.max_degree + 1;
   }
   else if ( menu -> props.network_p ) {
      max_edges =
         ( menu -> parms.vertex_count * menu -> parms.vertex_count ) -
         ( menu -> parms.vertex_count * 3 ) + 3;
      if ( menu -> parms.edge_count >= max_edges )
         menu -> parms.edge_count = max_edges;
   }
}

int illegal_parms( int files )
{
   if ( zero_vertex_or_edge_count() ) {
      warning( IllegalDimensions );
      return ( True );
   }
   else if ( bogus_file_name( files ) ) {
      warning( IllegalFileName );
      return ( True );
   }
   else {
      fix_imbalanced_graph();
      return ( False );
   }
}

void warning( char* message )
{
   printf( message );
}


/******************** graph generators **************************/

/* This function writes a pair of isomorphic, regular,
   undirected graphs to two files and writes an isomorphism to a third
   file.

   To  generate  a  pair  of isomorphic simple and regular
   graphs,  we  first  generate  a  random  simple  and regular
   graph.  We then construct an isomorphic copy by renaming its
   vertices using a random permutation.

   To generate a random simple graph
   in   which  every  vertex  has  degree  r, we  execute  the
   following,  which  we  subsequently  refer  to  as  the main
   procedure:

     1.   Choose  vertices  v and w each of degree less than
          r  such  that there is no edge between v and w. If
          no such pair exists, execute the fixup procedure.

     2.   Add an edge between v and w.

     3.   If some vertex has degree less than r, go to 1.

   The  fixup  procedure  works as follows. There are two cases
   to consider:

     1.   All vertices except one have degree equal to r.

     2.   There  are  pairs  of vertices each of degree less
          than  r,  but  each  such  pair is connected by an
          edge.

   In  the  first case, we increase the edge count in the graph
   in  the following way. Suppose that vertex v has degree less
   than  r.  Choose an edge (w1,w2) such that (v,w1) and (v,w2)
   are  not edges. Delete the edge (w1,w2) and add edges (v,w1)
   and  (v,w2).  In the second case, we increase the edge count
   in  the graph in a similar way. Suppose that vertices v1 and
   v2  have  degree  less than r and (v1,v2) is an edge. Choose
   an  edge  (w1,w2)  such  that  (v1,w1)  and  (v2,w2) are not
   edges.  Delete  the  edge  (w1,w2) and add edges (v1,w1) and
   (v2,w2).  If  some  vertex in the resulting graph has degree
   less than r, we resume by executing the main procedure.
 */
void isomorphic_graph_pair( int vertices,
                            int spec_degree,
                            char* first,
                            char* second,
                            char* third )
{
   Record  *records, *ptr;
   int     i, j,
           size = vertices * vertices,
           edge_count = 0,
           edges = ( vertices * spec_degree ) / 2,
           base, offset, index1, index2, index3,
           v, v1, v2,
           w, w1, w2,
           *adj_matrix,
           *vertex_degree,
           *aux,
           *aliases;
   FILE    *fptr;

   /* adjacency matrix to represent graph */
   if ( ( adj_matrix = ( int * ) calloc( size, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      return;
   }

   /* vectors to hold degree count per vertex */
   if ( ( vertex_degree = ( int * ) calloc( vertices, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      free( adj_matrix );
      return;
   }
   if ( ( aux = ( int * ) calloc( vertices, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      free( adj_matrix );
      free( vertex_degree );
      return;
   }

   /* vector to hold renamed vertices */
   if ( ( aliases = ( int * ) calloc( vertices, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      free( adj_matrix );
      free( vertex_degree );
      free( aux );
      return;
   }
   
   /* file entries to be sorted to get isomorphic graph */
   if ( ( records = ( Record * ) calloc( edges, sizeof( Record ) ) ) == NULL ) {
      warning( InsufficientStorage );
      free( adj_matrix );
      free( vertex_degree );
      free( aux );
      free( aliases );
      return;
   }
   else
      ptr = records;
   
   /* Initialize adjacency matrix for random permutation. */
   init_array( aux, vertices );

   /* loop until every vertex has spec_degree */
   while ( edge_count < edges ) {
      permute( aux, vertices );
      w = -1;
      /* Look for 2 vertices whose degree is less than r.
         If found & no edge, put in an edge & repeat.
         If we can find 2 vertices whose degree 
         is less than r, but each such pair is joined by an edge,
         set w != -1 and record one such pair as v1, w1.
         If there is no pair of vertices whose degree is less than r,
         w will still be -1 and there will be
         exactly one vertex v whose degree is less than r.  */
      for ( i = 0; i < vertices; i++ ) {
         if ( vertex_degree[ aux[ i ] ] < spec_degree ) {
            v = aux[ i ];
            for ( j = i + 1; j < vertices; j++ ) {
               if ( vertex_degree[ aux[ j ] ] < spec_degree ) {
                  w = aux[ j ];
                  base = min( v, w );
                  offset = max( v, w );
                  index1 = ( base * vertices ) + offset;
                  if ( !adj_matrix[ index1 ] ) { /* no edge so add one */
                     adj_matrix[ index1 ] = 1;
                     vertex_degree[ v ]++;
                     vertex_degree[ w ]++;
                     goto next;
                  }
                  else { /* save the vertices where there is an edge */
                     v1 = v;
                     w1 = w;
                  }
               }
            }
         }
      }
      if ( w == -1 ) { /* only one vertex v with degree < spec_degree */
         v1 = v;
         /* Find an edge (v2,w2) such that

               v2 != v1 && w2 != v1 && there are no edges (v1,v2)
               and (v1,w2).

            Add edges (v1,v2) and (v1,w2) and delete edge (v2,w2).  */
         for ( i = 0; i < vertices - 1; i++ ) {
            if ( v1 != ( v2 = aux[ i ] ) ) {
               base = min( v1, v2 );
               offset = max( v1, v2 );
               index1 = ( base * vertices ) + offset;
               if ( !adj_matrix[ index1 ] ) {
                  for ( j = i + 1; j < vertices; j++ ) {
                     if ( ( w2 = aux[ j ] ) != v1 ) {
                        base = min( v2, w2 );
                        offset = max( v2, w2 );
                        index2 = ( base * vertices ) + offset;
                        base = min( v1, w2 );
                        offset = max( v1, w2 );
                        index3 = ( base * vertices ) + offset;
                        if ( adj_matrix[ index2 ]  &&  !adj_matrix[ index3 ] ) {
                           adj_matrix[ index1 ] =
                              adj_matrix[ index3 ] = 1;
                           adj_matrix[ index2 ] = 0;
                           vertex_degree[ v1 ]++;
                           vertex_degree[ v1 ]++;
                           goto next;
                        }
                     }
                  }
               }
            }
         }
      }
      else {  /* two vertices v1 and w1 with degree < spec_degree */
         /* Find an edge (v2,w2) such that

               v2 != v1 && w1 != v2 && w2 != v1 && w2 != w1
               and there are no edges (v1,v2) and (w1,w2).

            Add edges (v1,v2) and (w1,w2) and delete edge (v2,w2).

            [Note that both loops must run from 0 to n-1 since
            there is an asymmetry in the conditions. For example,
            there might be an edge (v2,w2) such that there is an
            edge (v1,v2) yet there are no edges (v1,w2) and (w1,v2).]      */
         for ( i = 0; i < vertices; i++ ) {
            if ( v1 != ( v2 = aux[ i ] ) && v2 != w1 ) {
               base = min( v1, v2 );
               offset = max( v1, v2 );
               index1 = ( base * vertices ) + offset;
               if ( !adj_matrix[ index1 ] ) {
                  for ( j = 0; j < vertices; j++ ) {
                     if ( ( w2 = aux[ j ] ) != v1 && w2 != w1 ) {
                        base = min( v2, w2 );
                        offset = max( v2, w2 );
                        index2 = ( base * vertices ) + offset;
                        base = min( w1, w2 );
                        offset = max( w1, w2 );
                        index3 = ( base * vertices ) + offset;
                        if ( adj_matrix[ index2 ]  &&  !adj_matrix[ index3 ] ) {
                           adj_matrix[ index2 ] = 0;
                           adj_matrix[ index1 ] =
                              adj_matrix[ index3 ] = 1;
                           vertex_degree[ v1 ]++;
                           vertex_degree[ w1 ]++;
                           goto next;
                        }
                     }
                  }
               }
            }
         }
      }
      next: edge_count++;
   }

   /* print original graph */
   print_graph( vertices, edges, first, adj_matrix, Undirected );
   
   /* print an isomorphism */
   rename_vertices( aliases, vertices );
   if ( ( fptr = fopen( third, "w" ) ) == NULL ) {
      printf( "\n\t\tCould not open file %s.\n\n", third );
      free( adj_matrix );
      free( vertex_degree );
      free( aux );
      free( aliases );
      free( records );
      return;
   }
   else 
      for ( i = 0; i < vertices; i++ )
         fprintf( fptr, "%5d  %5d\n", i + 1, aliases[ i ] + 1 );
   fclose( fptr );

   /* print a graph isomorphic to the original:
        -- change edge names to aliases
        -- sort file to help disguise isomorphism
   */
   if ( ( fptr = fopen( first, "r" ) ) == NULL ) {
      printf( "\n\t\tCould not open file %s.\n\n", first );
      free( adj_matrix );
      free( vertex_degree );
      free( aux );
      free( aliases );
      free( records );
      return;
   }
   else {
      fgets( ptr -> record, RecordSize, fptr ); /* 1st record, vertex and edge count, is ignored */
      while ( ( fgets( ptr -> record, RecordSize, fptr ) ) != NULL )
         ptr++;
      fclose( fptr );
      rename_edges( records, aliases, edges );
      qsort( ( void * ) records, edges, sizeof( Record ), compare_strings );
      if ( ( fptr = fopen( second, "w" ) ) == NULL ) {
         printf( "\n\t\tCould not open file %s.\n", second );
         free( adj_matrix );
         free( vertex_degree );
         free( aux );
         free( aliases );
         free( records );
         return;
      }
      else {
         fprintf( fptr, "%5d   %5d\n", vertices, edges );
         ptr = records;
         for ( i = 0; i < edges; i++ ) {
            fprintf( fptr, "%s\n", ptr -> record );
            ptr++;
         }
      }
   }
   fclose( fptr );
   
   free( adj_matrix );
   free( vertex_degree );
   free( aux );
   free( aliases );
   free( records );
}

/* This function serves the same purpose as strcmp.  However,
   the arguments in compare_strings are of type const void*, thus
   providing compatibility with the ANSI function prototype header for qsort.
   If strcmp is substituted for compare_strings in the qsort
   invocation, in ANSI C a warning will be issued.
   (Notice that in ANSI C, the const void* types are automatically converted to
   const char* when strcmp is called.)
 */
int compare_strings( const void* a, const void* b )
{
   return strcmp( a, b );
}

void rename_vertices( int* aliases, int count )
{
   init_array( aliases, count );
   permute( aliases, count );
}

void rename_edges( Record* ptr, int* aliases, int count )
{
   int   i, vertex1, vertex2, v1, v2;
   char  buffer[ RecordSize ];

   for ( i = 0; i < count; i++ ) {
      sscanf( ptr -> record, "%5d  %5d",
              &vertex1, &vertex2 );
      if ( ( v1 = aliases[ vertex1 - 1 ] + 1 ) <
           ( v2 = aliases[ vertex2 - 1 ] + 1 ) )
         sprintf( buffer, "%5d   %5d   %5d", v1, v2, 1 );
      else
         sprintf( buffer, "%5d   %5d   %5d", v2, v1, 1 );
      strcpy( ptr -> record, buffer );
      ptr++;
   }
}

/* This function generates a random connected simple graph with
   v vertices and max(v-1,e) edges.  The graph can be weighted
   (weight_flag == 1) or unweighted (weight_flag != 1). If
   it is weighted, the weights are in the range 1 to max_wgt.
   It is assumed that e <= v(v-1)/2. (In this program, this assured
   because of the call to fix_imbalanced_graph.)

   To  generate  a  random  connected  graph,  we begin by
   generating  a  random  spanning  tree.  To generate a random
   spanning  tree,  we  first  generate  a  random  permutation
   tree[0],...,tree[v-1]. (v = number of vertices.)
   We  then  iteratively  add edges  to form a
   tree.  We  begin with the tree consisting of vertex tree[0] and
   no   edges.   At   the   iterative   step,  we  assume  that
   tree[0],tree[1],...,tree[i-1]  are  in  the  tree.  We  then add vertex
   tree[i]  to     the    tree    by    adding    the    edge
   (tree[i],tree[rand(i)]).  (This  construction  is similar to
   that  of  Prim's algorithm.) Finally, we add random edges to
   produce the desired number of edges.
 */
void random_connected_graph( int v,
                             int e,
                             int max_wgt,
                             int weight_flag,
                             char* out_file )
{
   int i, j, count, index, *adj_matrix, *tree;

   if ( ( adj_matrix = ( int * ) calloc( v * v, sizeof( int ) ) )
        == NULL ) {
      printf( "Not enough room for this size graph\n" );
      return;
   }

   if ( ( tree = ( int * ) calloc( v, sizeof( int ) ) ) == NULL ) {
      printf( "Not enough room for this size graph\n" );
      free( adj_matrix );
      return;
   }

   printf( "\n\tBeginning construction of graph.\n" );

   /*  Generate a random permutation in the array tree. */
   init_array( tree, v );
   permute( tree, v );

   /*  Next generate a random spanning tree.
       The algorithm is:

         Assume that vertices tree[ 0 ],...,tree[ i - 1 ] are in
         the tree.  Add an edge incident on tree[ i ]
         and a random vertex in the set {tree[ 0 ],...,tree[ i - 1 ]}.
    */

   for ( i = 1; i < v; i++ ) {
      j = ran( i );
      adj_matrix[ tree[ i ] * v + tree[ j ] ] =
         adj_matrix[ tree[ j ] * v + tree[ i ] ] =
         weight_flag ? 1 + ran( max_wgt ) : 1;
   }

   /* Add additional random edges until achieving at least desired number */

   for ( count = v - 1; count < e; ) {
      i = ran( v );
      j = ran( v );

      if ( i == j )
         continue;

      if ( i > j )
         swap( &i, &j );

      index = i * v + j;
      if ( !adj_matrix[ index ] ) {
         adj_matrix[ index ] = weight_flag ? 1 + ran( max_wgt ) : 1;
         count++;
      }
   }

   print_graph( v, count, out_file, adj_matrix, Undirected );

   free( tree );
   free( adj_matrix );
}

/* This function generates a random undirected graph with
   v vertices and e edges.  The graph can be weighted
   (weight_flag == 1) or unweighted (weight_flag != 1). If
   it is weighted, the weights are in the range 1 to max_wgt.
   The graph can be simple (simple_flag == 1) or not simple
   (simple_flag != 1). If the graph is simple, it is assumed
   that e <= v(v-1)/2. (In this program, this assured because
   of the call to fix_imbalanced_graph.)
 */
void random_graph( int v,
                   int e,
                   int max_wgt,
                   int weight_flag,
                   int simple_flag,
                   char* out_file )
{
   int i, j, count, index, *adj_matrix;

   /* generate a not necessarily simple random graph */
   if ( !simple_flag ) {
      r_graph( v, e, max_wgt, weight_flag, out_file );
      return;
   }

   /* generate a simple random graph */
   if ( ( adj_matrix = ( int * ) calloc( v * v, sizeof( int ) ) )
        == NULL ) {
      printf( "Not enough room for this size graph\n" );
      return;
   }

   for ( count = 0; count < e; ) {
      i = ran( v );
      j = ran( v );

      if ( i == j )
         continue;

      if ( i > j )
         swap( &i, &j );

      index = i * v + j;
      if ( !adj_matrix[ index ] ) {
         adj_matrix[ index ] = weight_flag ? 1 + ran( max_wgt ) : 1;
         count++;
      }
   }

   print_graph( v, e, out_file, adj_matrix, Undirected );

   free( adj_matrix );
}

/* This function generates a random, not necessarily simple
   graph. The graph can be weighted (weight_flag == 1)
   or unweighted (weight_flag != 1). It can be interpreted
   as directed or undirected.

   Random edges are generated and written directly to the
   output file.
 */
void r_graph( int v,
              int e,
              int max_wgt, int weight_flag,
              char* out_file )
{
   FILE *fp;
   int i;

   if ( ( fp = fopen( out_file, "w" ) ) == NULL ) {
      printf( "Unable to open file %s for writing\n", out_file );
      return;
   }

   printf( "\n\tWriting graph to file %s.\n", out_file );

   fprintf( fp, "%5d   %5d\n", v, e );

   for ( i = 0; i < e; i++ )
      fprintf( fp, "%5d   %5d   %5d\n", 1 + ran( v ), 1 + ran( v ),
               weight_flag ? 1 + ran( max_wgt ) : 1 );

   printf( "\tGraph is written to file %s.\n", out_file );
   fclose( fp );
}

/* This function generates a random directed graph with
   v vertices and e edges.  The graph can be weighted
   (weight_flag == 1) or unweighted (weight_flag != 1). If
   it is weighted, the weights are in the range 1 to max_wgt.
   The graph can be simple (simple_flag == 1) or not simple
   (simple_flag != 1). If the graph is simple, it is assumed
   that e <= v(v-1). (In this program, this assured because
   of the call to fix_imbalanced_graph.)
 */
void random_digraph( int v,
                     int e,
                     int max_wgt,
                     int weight_flag,
                     int simple_flag,
                     char* out_file )
{
   int i, j, count, index, *adj_matrix;

   /* generate a not necessarily simple random digraph */
   if ( !simple_flag ) {
      r_graph( v, e, max_wgt, weight_flag, out_file );
      return;
   }

   /* generate a simple random digraph */
   if ( ( adj_matrix = ( int * ) calloc( v * v, sizeof( int ) ) )
        == NULL ) {
      printf( "Not enough room for this size graph\n" );
      return;
   }

   for ( count = 0; count < e; ) {
      i = ran( v );
      j = ran( v );

      if ( i == j )
         continue;

      index = i * v + j;
      if ( !adj_matrix[ index ] ) {
         adj_matrix[ index ] = weight_flag ? 1 + ran( max_wgt ) : 1;
         count++;
      }
   }

   print_graph( v, e, out_file, adj_matrix, Directed );
   free( adj_matrix );
}

/* This function writes a directed acyclic graph to one file and a
   topological sort to a second file. The graph can be weighted or
   unweighted. It is assumed that e <= v(v-1)/2. (In this program,
   this assured because of the call to fix_imbalanced_graph.)

   To   generate   a  directed  acyclic  graph,  we  first
   generate  a  random  permutation  dag[0],...,dag[v-1].
   (v = number of vertices.)
   This random permutation serves as a topological
   sort  of  the  graph. We then generate random edges of the
   form (dag[i],dag[j]) with i < j.
 */
void directed_acyclic_graph( int v,
                             int e,
                             int max_wgt,
                             int weight_flag,
                             char* out_file,
                             char* dag_file )
{
   int i, j, count, index, *adj_matrix, *dag;
   FILE *fptr;

   if ( ( adj_matrix = ( int * ) calloc( v * v, sizeof( int ) ) )
        == NULL ) {
      printf( "Not enough room for this size graph\n" );
      return;
   }

   if ( ( dag = ( int * ) calloc( v, sizeof( int ) ) ) == NULL ) {
      printf( "Not enough room for this size graph\n" );
      free( adj_matrix );
      return;
   }

   printf( "\n\tBeginning construction of graph.\n" );

   /*  Generate a random permutation in the array dag. */
   init_array( dag, v );
   permute( dag, v );

   for ( count = 0; count < e; ) {
      if ( ( i = ran( v ) ) == ( j = ran( v ) ) )
         continue;
      if ( i > j )
         swap( &i, &j );
      i = dag[ i ];
      j = dag[ j ];
      index = i * v + j;
      if ( !adj_matrix[ index ] ) {
         adj_matrix[ index ] = weight_flag ? 1 + ran( max_wgt ) : 1;
         count++;
      }
   }

   print_graph( v, e, out_file, adj_matrix, Directed );

   if ( ( fptr = fopen( dag_file, "w" ) ) == NULL )
      printf( "\n\t\t Could not open file %s.\n", dag_file );
   else {
      for ( i = 0; i < v; i++ )
         fprintf( fptr, "%5d\n", 1 + dag[ i ] );
      fclose( fptr );
   }

   free( adj_matrix );
   free( dag );
}

/* This function generates a weighted complete graph.  The
   graph can be directed or not.
 */
void complete_graph( int v,
                     int max_wgt,
                     int dir_flag,
                     char* out_file )
{
   int i, j;
   FILE *fp;

   if ( ( fp = fopen( out_file, "w" ) ) == NULL ) {
      printf( "Unable to open file %s for writing.\n", out_file );
      return;
   }
   printf( "\n\tWriting graph to file %s.\n", out_file );

   fprintf( fp, "%5d   %5d\n", v,
            dir_flag ? v * ( v - 1 ) : v * ( v - 1 ) / 2 );

   for ( i = 1; i < v; i++ )
      for ( j = i + 1; j <= v; j++ ) {
         fprintf( fp, "%5d   %5d   %5d\n", i, j, 1 + ran( max_wgt ) );
         if ( dir_flag )
            fprintf( fp, "%5d   %5d   %5d\n", j, i, 1 + ran( max_wgt ) );
      }

   fclose( fp );

   printf( "\tGraph is written to file %s.\n", out_file );
}

/* This function writes a simple graph with a Hamiltonian cycle to one
   file and a Hamiltonian cycle to another file. The graph will
   have max(e,v) edges. The graph can be directed or undirected. It is
   assumed that e <= v(v-1)/2 if the graph is undirected, and that
   e <= v(v-1) if the grpah is directed. (In this program,
   this assured because of the call to fix_imbalanced_graph.)

   To generate a random graph with a
   Hamiltonian cycle, we begin with a random permutation
   ham[0],...,ham[v-1] (v = number of vertices).  We then generate edges

   (ham[0],ham[1]),(ham[1],ham[2]),...,(ham[v-2],ham[v-1]),(ham[v-1],ham[0]),

   so that the graph has the Hamiltonian cycle

                     ham[0],...,ham[v-1],ham[0].

   Finally,  we  add random edges to produce the desired number
   of edges.
 */
void hamiltonian_cycle_graph( int v,
                              int e,
                              int dir_flag,
                              char* out_file,
                              char* ham_file )
{
   int i, j, k, l, count, index, *adj_matrix, *ham;
   FILE *fptr;

   if ( ( adj_matrix = ( int * ) calloc( v * v, sizeof( int ) ) )
        == NULL ) {
      printf( "Not enough room for this size graph\n" );
      return;
   }

   if ( ( ham = ( int * ) calloc( v, sizeof( int ) ) ) == NULL ) {
      printf( "Not enough room for this size graph\n" );
      free( adj_matrix );
      return;
   }

   printf( "\n\tBeginning construction of graph.\n" );

   /*  Generate a random permutation in the array ham. */
   init_array( ham, v );
   permute( ham, v );

   if ( ( fptr = fopen( ham_file, "w" ) ) == NULL ) {
      printf( "\n\t\t Could not open file %s.\n", ham_file );
      free( adj_matrix );
      free( ham );
      return;
   }

   /* print Hamiltonian cycle and store required edges */
   for ( i = 0; i < v; i++ ) {
      fprintf( fptr, "%5d\n", 1 + ham[ i ] );
      k = ham[ i ];
      l = ham[ ( i + 1 ) % v ];
      if ( k > l && !dir_flag )
         swap( &k, &l );
      adj_matrix[ k * v + l ] = 1;
   }

   fprintf( fptr, "%5d\n", 1 + ham[ 0 ] );
   fclose( fptr );
   free( ham );

   for ( count = v; count < e; ) {
      if ( ( i = ran( v ) ) == ( j = ran( v ) ) )
         continue;
      if ( i > j && !dir_flag )
         swap( &i, &j );
      index = i * v + j;
      if ( !adj_matrix[ index ] ) {
         adj_matrix[ index ] = 1;
         count++;
      }
   }

   print_graph( v, count, out_file, adj_matrix, dir_flag );
}

/* This function generates a random network.  The user selects
   the number of vertices (v) and edges (e), the maximum weight per edge, and the
   the output file name. It is assumed that e <= v**2 - 3v + 3. (In this
   program, this assured because of the call to fix_imbalanced_graph.) The
   function will produce a network with at least e edges. In some rare,
   cases, the actual number of edges may be slightly more than e because
   of the following:

      Each vertex is guaranteed to be on a directed path from the source
      to the sink. This is achieved by generating random directed paths
      from the source to the sink until every vertex is on such a path.
 */
void network_flow_graph( int vertices,
                         int edges,
                         int max_weight,
                         char* outfile )
{
   int  start = 0,
        finish = vertices - 1,
        edge_count = 0,
        from, to,
        *adj_matrix,
        *closed_list;

   if ( vertices == 1 ) {
      warning( SingleVertexNetwork );
      return;
   }

   /* adjacency matrix to represent graph */
   if ( ( adj_matrix = ( int * ) calloc( vertices * vertices, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      return;
   }

   /* closed_list[ i ] == True if vertices[ i ] is on some path from start to finish */
   if ( ( closed_list = ( int * ) calloc( vertices, sizeof( int ) ) ) == NULL ) {
      warning( InsufficientStorage );
      free( adj_matrix );
      return;
   }

   /* put each vertex on some path from start to finish */
   closed_list[ start ] = True;
   do {
      /* from start to some vertex not already picked */
      to = pick_to( closed_list, vertices );
      adj_matrix[ to ] = ran( max_weight ) + 1;
      edge_count++;

      /* from current vertex to vertex != finish */
      if ( to != finish ) {
         from = to;
         closed_list[ finish ] = False;
         while ( ( to = pick_to( closed_list, vertices ) ) != finish ) {
            adj_matrix[ from * vertices + to ] = ran( max_weight ) + 1;
            edge_count++;
            from = to;
         }

         /* from vertex to finish */
         adj_matrix[ from * vertices + finish ] = ran( max_weight ) + 1;
         edge_count++;
      }
   } while ( unpicked_vertices_p( closed_list, vertices ) );

   /* add additional edges as needed */
   while ( edge_count < edges ) {
      from = ran( vertices - 1 );
      to = pick_to( NULL, vertices );
      if ( !adj_matrix[ from * vertices + to ]  &&  from != to ) {
         adj_matrix[ from * vertices + to ] = ran( max_weight ) + 1;
         edge_count++;
      }
   }
   print_graph( vertices, edge_count, outfile, adj_matrix, Directed );

   /* free storage */
   free( adj_matrix );
   free( closed_list );
}

int pick_to( int* closed, int vertices )
{
   int  vertex;

   if ( closed == NULL )        /* pick any vertex, even if picked before... */
      do {
         vertex = ran( vertices );
      } while ( vertex == 0 );  /* ...except for start */
   else {
      do {
         vertex = ran( vertices );
      } while ( closed[ vertex ] );
      closed[ vertex ] = True;
   }
   return ( vertex );
}

int unpicked_vertices_p( int* closed, int n )
{
   int  i = 1;

   while ( i < n )
      if ( !closed[ i ] )
         return ( True );
      else
         i++;
   return ( False );
}

/*** ran, etc. ***/
void seed_ran( void )
{
   srand( ( unsigned short ) time( NULL ) );
}

/* Return a random integer between 0 and k-1 inclusive. */
int ran( int k )
{
   return rand() % k;
}

void print_graph( int v,
                  int e,
                  char* out_file,
                  int* adj_matrix,
                  int dir_flag )
{
   int i, j, index;
   FILE *fp;

   if ( ( fp = fopen( out_file, "w" ) ) == NULL ) {
      printf( "Unable to open file %s for writing.\n", out_file );
      return;
   }
   printf( "\n\tWriting graph to file %s.\n", out_file );

   fprintf( fp, "%5d   %5d\n", v, e );

   if ( !dir_flag )
      for ( i = 1; i < v; i++ )
         for ( j = i + 1; j <= v; j++ ) {
            index = ( i - 1 ) * v + j - 1;
            if ( adj_matrix[ index ] )
               fprintf( fp, "%5d   %5d   %5d\n", i, j, adj_matrix[ index ] );
         }
   else
      for ( i = 1; i <= v; i++ )
         for ( j = 1; j <= v; j++ ) {
            index = ( i - 1 ) * v + j - 1;
            if ( adj_matrix[ index ] )
               fprintf( fp, "%5d   %5d   %5d\n", i, j, adj_matrix[ index ] );
         }
   fclose( fp );
   printf( "\tGraph is written to file %s.\n", out_file );
}

/* randomly permute a[ 0 ],...,a[ n - 1 ] */
void permute( int* a, int n )
{
   int i;

   for ( i = 0; i < n - 1; i++ )
      swap( a + i + ran( n - i ), a + i );
}

void swap( int* a, int *b )
{
   int temp;

   temp = *a;
   *a = *b;
   *b = temp;
}

/* set a[ i ] = i, for i = 0,...,end - 1 */
void init_array( int* a, int end )
{
   int i;

   for ( i = 0; i < end; i++ )
      *a++ = i;
}

/* Get integer input from user. If not an int, prompt for correct
   value. indent gives the proper indentation for error message.
 */
int get_int( char* indent )
{
   char buff[ 30 ];
   int val;

   for ( ; ; ) {
      scanf( "%s", buff );
      if ( sscanf( buff, "%d", &val ) != 1 )
         printf( "%s%s", indent, "***** Illegal input.  Reenter value: " );
      else
         return val;
   }
}

关闭提示 关闭

确 认 取 消
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值