/* SI 335 Spring 2012
* Project 6
* This is a program to generate test cases for the "drive"
* shortest-paths finder program. It takes in n and m and
* writes a randomly-generated graph to the named output file.
*/
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
// Returns a random integer between 0 and n-1.
int randomInt(int n);
// Prints an error message and exits ungracefully
void error (const char* msg);
int main (int argc, char** argv) {
srand(time(NULL));
// Check command-line arguments
if (argc != 4) {
cerr << "Usage: " << argv[0] << " <n> <m> <output_file>" << endl;
error ("Wrong number of arguments");
}
int n, m;
n = atoi(argv[1]);
m = atoi(argv[2]);
if (n <= 0 || m <= 0) error ("n and m must be positive");
if (n > 10000) error ("n is too large");
if (m > n*(n-1)/2) error ("m is too large");
ofstream graph (argv[3]);
if (!graph) error("Bad output filename");
// Read in city names, then put into random order.
ifstream citynames ("cities.txt");
if (!citynames) error("Could not find file cities.txt");
vector<string> cities(n);
for (int i=0; i<n; ++i)
citynames >> cities[i];
citynames.close();
random_shuffle(cities.begin(), cities.end());
// Print n, m to graph file
graph << n << ' ' << m << endl;
// Print city names to graph file
for (int i=0; i<n; ++i)
graph << cities[i] << endl;
// Make a matrix to store whether we've already put
// an edge between two vertices.
bool** edges = new bool*[n];
edges[0] = new bool[n*n];
for (int i=1; i<n; ++i)
edges[i] = edges[i-1]+n;
if (m <= n*(n-1)/4) {
// Graph is (mostly) sparse. So start with empty graph and
// generate random edges.
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j)
edges[i][j] = false;
edges[i][i] = true;
}
int i=0;
// Start by generating a random tree, so the graph will be connected.
for (; i<n-1 && i<m; ++i) {
int u = i+1;
int v;
do { v = randomInt(u); } while (edges[u][v]);
graph << cities[u] << ' ' << cities[v] << ' ';
graph << randomInt(400) << ' ' << randomInt(400) << endl;
edges[u][v] = edges[v][u] = true;
}
// Now just generate random edges
for (; i<m; ++i) {
int u,v;
do {
u = randomInt(n);
v = randomInt(n);
} while (edges[u][v]);
graph << cities[u] << ' ' << cities[v] << ' ';
graph << randomInt(400) << ' ' << randomInt(400) << endl;
edges[u][v] = edges[v][u] = true;
}
}
else {
// Graph is (mostly) dense. So start with a complete graph and randomly
// remove edges.
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j)
edges[i][j] = true;
edges[i][i] = false;
}
for (int i=m; i<n*(n-1)/2; ++i) {
int u,v;
do {
u = randomInt(n);
v = randomInt(n);
} while (!edges[u][v]);
edges[u][v] = edges[v][u] = false;
}
for (int i=0; i<n; ++i) {
for (int j=i+1; j<n; ++j) {
if (edges[i][j]) {
graph << cities[i] << ' ' << cities[j] << ' ';
graph << randomInt(400) << ' ' << randomInt(400) << endl;
}
}
}
}
graph.close();
delete [] edges[0];
delete [] edges;
return 0;
}
// Returns a random integer between 0 and n-1.
int randomInt(int n) {
int r, max = RAND_MAX - ((RAND_MAX-n+1) % n);
do { r = rand(); }
while (r > max);
return (r % n);
}
// Prints an error message and exits ungracefully
void error (const char* msg) {
cerr << "ERROR:" << endl << msg << endl;
exit(1);
}