import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

///////////////////////////////////////////////////////////////////////////////////////
//  Class for storing and managing an undirected, unweighted graph G, using an adjacency matrix.
//    NO ERROR CHECKING YET!!
//
//  For CS 422 Fall 2002, Northern Michigan University  (instructor:  J. Horn)
///////////////////////////////////////////////////////////////////////////////////////


public class Graph
	{

        private int [][] edges;      // adjacency matrix.  edges[i][j] == 1 if there is an edge
                                     // from vertex i to vertex j in G.  edges[i][j] == 0 otherwise.

        private int num_vertices = 0;
        private int num_edges = 0;
        private double density = 0.0;

        private int cost_so_far = 0;

		private void update_edge_density()
        		{
					if(num_vertices>1)
					   density = 2.0*num_edges/(num_vertices*(num_vertices-1.0));
					   else density = 0.0;
				}



        public Graph()
            {  }


		public Graph(Graph input_graph)
		    {
				put_adj_matrix(input_graph.get_adj_matrix());
		    }


        public int [][]  get_adj_matrix()      // In case someone wants it!   (give them a COPY.)
        									   // (what would happen if we just had "return edges;"?)
               {
				   int [][] copy_of_edges = new int[num_vertices][num_vertices];
				   for(int row=0; row< num_vertices; row++)
				       for(int column=0; column<num_vertices; column++)
				           copy_of_edges[row][column] = edges[row][column];

				   return copy_of_edges;
			   }


		///////////////////////////////////////////////////////////////////////////////////////
		// In case someone wants to give us a matrix!
		// (Make a COPY.  What could happen if we just had "edges;"?)
		///////////////////////////////////////////////////////////////////////////////////////

        public void put_adj_matrix(int [][] input_edges)
               {
				   num_vertices = input_edges[0].length;
				   num_edges = 0;
				   for(int row=0; row< num_vertices; row++)
				       for(int column=0; column<num_vertices; column++)
				           {
				             edges[row][column] = input_edges[row][column];
				             if(edges[row][column] ==1)
				                num_edges++;
						    }
				   update_edge_density();
			   }


 		public int get_num_vertices() {return num_vertices;}
 		public int get_num_edges()  {return num_edges;}
        public int get_cost_so_far() {return cost_so_far;}


		///////////////////////////////////////////////////////////////////////////////////////
		// Return the ACTUAL edge density of this graph, which is the number of edges divided by the
		// number of possible edges (= n(n-1)/2).
		///////////////////////////////////////////////////////////////////////////////////////

		public double get_edge_density()  {return density;}


		public boolean edgeQ(int i, int j)    // Return true if edge(i,j) in G, false otherwise
		       { cost_so_far++;
		         return true;}

		public boolean vertexQ(int i)  // Return true if vertex i in G, false otherwise.
		       {return i < num_vertices && 0 <= i;}


///////////////////////////////////////////////////////////////////////////////////////
//  Read in graphs from a local text file, assuming the file is in the format used in the
//   book "Combinatorial Algorithms:  Generation, Enumeration, and Search" (CAGES) by
//   Kreher and Stinson.  Data files can be found at
//            http://www.math.mtu.edu/~kreher/cages.html  click on "Data"
///////////////////////////////////////////////////////////////////////////////////////

		private void read_graph_from_CAGES_file(String file_name)
		  {
			String s;
			StringTokenizer st;
			String token;
			int row;
			int column;

			try
			{
			  BufferedReader input = new BufferedReader(new FileReader(file_name));
			  s = input.readLine();   //   First line has num_vertices
			  st = new StringTokenizer(s);      //  Tokenize first line
			  token = st.nextToken();       // Skip first number on first line.
			  token = st.nextToken();       // This is the number of vertices!
			  num_vertices = Integer.valueOf(token).intValue();

			  //  Start with correctly sized adj. matrix, zeroed out (no edges).
			  edges = new int[num_vertices][num_vertices];
			  num_edges=0;

			  s = input.readLine();   //   Start getting edges
			  while(s != null)
			     {
			       st = new StringTokenizer(s);      // tokenize line
			       row = Integer.valueOf(st.nextToken()).intValue();
			       column = Integer.valueOf(st.nextToken()).intValue();
			  	   edges[row][column] = 1;
			  	   edges[column][row] = 1;
			  	   num_edges++;
			  	   s = input.readLine();
			     }
			  input.close();
			 }
			 catch (Exception e)
			   {
			      e.printStackTrace();
			    }
			 update_edge_density();
		    }

///////////////////////////////////////////////////////////////////////////////////////
//  Write out graph to a local text file, putting the data into the file in the format used
//   in the book "Combinatorial Algorithms:  Generation, Enumeration, and Search" (CAGES) by
//   Kreher and Stinson.  Data files can be found at
//            http://www.math.mtu.edu/~kreher/cages.html  click on "Data"
///////////////////////////////////////////////////////////////////////////////////////

	public void write_graph_to_CAGES_file(String file_name)
	{
    	try
    	{
    		PrintStream output = new PrintStream(new FileOutputStream(file_name));

			output.println(num_edges + " " + num_vertices);   // first line

      		for(int row=0; row< num_vertices; row++)
				for (int column=row+1; column<num_vertices ;column++)
					if(edges[row][column]==1)
					   output.println(" "+row+" "+column);

      		output.println();  output.println();   				     // Print two extra lines,
      		output.flush();											 // just to conform to CAGES.
      		output.close();
    	}
    	catch(Exception e)
    	{
    		e.printStackTrace();
    	}
	}


		public void print()
			  {
				  System.out.println();
				  System.out.println();
				  System.out.println("ADJACENCY MATRIX");
				  System.out.println("--------------------------------------------------------------");
				  for(int i=0; i<num_vertices; i++)
				     {
						System.out.println();
				        for(int j=0; j<num_vertices; j++)
				            System.out.print(edges[i][j] + " ");
				     }
				  System.out.println("--------------------------------------------------------------");
		       }

	    public void paint(Graphics g)
	          {
				for(int i=0; i<num_vertices; i++)
				    for(int j=0; j<num_vertices; j++)
				            g.drawString(edges[i][j]+"", i*20, j*20);
	           }




///////////////////////////////////////////////////////////////////////////////////////
//  METHODS FOR CREDIT ON FINAL EXAM in CS 422
///////////////////////////////////////////////////////////////////////////////////////

		//  Add edge i,j to adj. matrix.  Keep symmetry about main diagonal!
		//  Do not allow a "self-loop" to be added (that is, an edge of the
		//  form [i,i]).
		//   <= 5 pts.
		public void add_edge(int i, int j)  {}


        // Return true if the set of vertices "list_of_vertices" is a clique in G.
        //  Return false otherwise.
        //   <= 15 pts. for code.   <= 5 additional points for run-time analysis
        public boolean cliqueQ(int [] list_of_vertices)  {return false;}


		//  Return true if given graph input_G is a subgraph of G.  Note that you do not
		//  have to check isomorphism.  For input_G to be a subgraph of G, the edges in
		//  in input_G must be a subset of the edges in G, that is all.  Return false
		//  otherwise.
		//  <= 5 points for code.  <= 5 additional points for run-time analysis.
		public boolean subgraphQ(Graph input_G) {return true;}


		//  Return true if graph input_G is isomorphic to G.  (Note that this is not
		//  "subgraph isomorphism".)  Return false otherwise.
		//  <= 5 points for code.  <= 5 pts additional for run-time analysis.
		public boolean isomorphicQ(Graph input_G) {return false;}


		//  Create a new graph with input_num_vertices, and enough edges, randomly
		//  distributed, to give an edge density of approximately input_density.
		//  (See definition of "density" in comments above.)
		//  <= 20 points for code.  <= 5 points additional for run-time analysis.
		public void randomize(int input_num_vertices, double input_density) {}


		//  Replace G with the complement of G.
		//  <= 10 points for code.   <= 5 points for run-time analysis.
		public void complement()  {}


		//  Return true if and only if there exists a path (sequence of adjacent
		//  vertices) in G that visits each vertex exactly once, and then returns
		//  to the first vertex on the path.  Return false otherwise.
		//  <= 30 points for code.  <=  20 points additional for run-time analysis.
		public boolean hamiltonianCircuitQ() {return true;}

		//  Return true if and only if there exists an "Euler path" (sequence of
		//  adjacent vertices) in G that includes EVERY EDGE exactly once.  Return
		//  false otherwise.  Note that the question here is the existence of a
		//  PATH with the Euler property, not a CIRCUIT.  Thus the path does not have
		//  to be "closed" (i.e., returns to the first vertex on the path).
		//  Look up definition of Euler path in a discrete math textbook or on the
		//  web.  There is a simple algorithm, really just an equation, for solving.
		//  <= 10 points for code.   <= 5 points additional for run-time analysis.
		public boolean eulerPathQ() {return false;}


		//  Return true if G is a connected graph (no isolated vertices).
		//  Return false otherwise.  Note that is not the same as "completely
		//  connected graph", in which every pair of vertices is connected.
		//  See below for that method!
		//  <= 10 points for code.  <= 5 points for run-time analysis
		public boolean connectedGraphQ() {return true;}


		//  Return true if graph G has the "planar graph" quality.  Return
		//  false otherwise.  "Planar" means that it can be drawn in the 2d plane
		//  such that no edges cross.  There is a simple algorithm (really just an
		//  equation) for this.  Look in any discrete math text book or on the web.
		//  <= 10 points for code.   <= 5 points additional for run-time analysis.
		public boolean planarGraphQ() {return false;}


		//  Return true if G is a completely connected graph.  Return false
		//  otherwise.  "completely connected" means every pair of vertices
		//  has an edge in G.  To put it another way, the complement of a
		//  completely connected graph has no edges it it!  Note that you should
		//  NOT add "self-loops" (no edges of type [i,i]).
		//  <= 5 points for code.  <= 5 points additional for run-time analysis.
		public boolean completeGraphQ() {return false;}


		//  Add all missing edges to graph G in order to make it "complete".
		//  But do not add "self-loops" (edges from vertex i to vertex i).  This
		//  means keeping the "main diagonal" in the adj. matrix all zeros!
		//  <= 5 points for code.  <= 5 points additional for run-time analysis.
		public void make_complete_graph() {}

		//  This is really just a useful "repair" method.  If someone adds an edge
		//  [i,j] in the adj. matrix, then the corresponding edge [j,i] should also
		//  be in the matrix, if this is to be an undirected graph.  This method
		//  provides a way for programmers to make sure that the adj. matrix is
		//  symmetric about the main diagonal, as it must be for an undirected graph.
		//  Note:  only turn 0s into 1s.  If [i,j] is 0 and [j,i] is 1, make them
		//  BOTH 1, not both 0.
		//  <= 10 points for code.   <= 5 points additional for run-time analysis.
		public void make_undirected_graph() {};

		//  Return a list of integers (vertices) representing the largest clique in G.
		//  If there are multiple such max-cliques, then return any one of them.
		//  <= 35 points for code.   <= 20 points for analysis
		public int [] max_clique() {int[] p ={1,2}; return p; }

		//  Return an int that is the number of vertices in the maximum size clique of
		//  G.  Note:  just call "max_clique()" above.
		//  <= 5 points for code.  <= 5 points additional for run-time analysis.
		public int max_clique_size() {return 2;}


		// Return true if and only if there is a clique of size k vertices in
		// the graph G.  Return false otherwise.  Note that is means a clique of
		// EXACTLY size k, not less than or equal to size k (in which case you could
		// have simply called max_clique_size() above and checked to see if it returned
		// a value less than or equal to k), or greater than or equal to k.
		// <= 25 points for code.  <= 15 points additional for run-time analysis.
		public boolean k_cliqueQ(int k) {return true;}



///////////////////////////////////////////////////////////////////////////////////////
//  MAIN code for testing methods in class Graph above.
///////////////////////////////////////////////////////////////////////////////////////

	    public static void main(String args [])
	           {
				   Graph G = new Graph();
				   G.print();
				   G.read_graph_from_CAGES_file("rand125_75.txt");
				   G.print();
				   System.out.println(G.get_num_vertices());
				   System.out.println(G.get_num_edges());
				   System.out.println(G.get_edge_density());
				   G.write_graph_to_CAGES_file("test125_75.txt");
			}



	}

