traveling-salesman / MST.cpp
MST.cpp
Raw
// Project Identifier: 9B734EC0C043C5A836EA0EBE4BEFEA164490B2C7
#include <map>
#include <cmath>
#include <vector>
#include <string>
#include <limits>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <getopt.h>
#include <algorithm>
#include <unordered_map>
#include "MST.h"


////////////
//INPUT
//utilities
bool is_land(Pokemon &pokemon){
    if(pokemon.x > 0 && pokemon.y > 0){
        return true;
    }
    return false;
}

bool is_coast(Pokemon &pokemon){
     if(pokemon.x <= 0 && pokemon.y == 0){
        return true;
    }
    else if(pokemon.x == 0 && pokemon.y <= 0){
        return true;
    }
    return false;
}
    
bool is_sea(Pokemon &pokemon){
     if(pokemon.x < 0 && pokemon.y < 0){
        return true;
    }
    return false;  
}

//get pokemon
void get_pokemon(vector<Pokemon> &container){
    //get pokemon num
    size_t num;
    cin >> num;
    //for pokemon num, cin pokemon and add to vector
    for(size_t i=0; i < num; i++){
        int x, y;
        cin >> x >> y;
        Pokemon new_pokemon = Pokemon(i, x, y);
        if(is_sea(new_pokemon)){
            new_pokemon.is_sea = true;
        }
        else if(is_coast(new_pokemon)){
            new_pokemon.is_coast = true;
        }
        else{
            new_pokemon.is_land = true;
        }
        container.push_back(new_pokemon);
    }
}

//euclidean distance
double find_the_distance(double &ax, double &ay, double &bx, double &by){
    return sqrt((double)pow((bx - ax), 2) + pow((by - ay), 2));
}

//returns weight from two pokemon
double find_the_weight(Pokemon &pokemon_a, Pokemon &pokemon_b){
    return find_the_distance(pokemon_a.x, pokemon_a.y, pokemon_b.x, pokemon_b.y);
}

//PART A
void check_the_mst(vector<Pokemon> &container){
    int land_num = 0;
    int sea_num = 0;
    int coast_num = 0;
    for(size_t i=0; i< container.size(); i++){
        if(container[i].x > 0 && container[i].y > 0){
            land_num++;
        }
        else if(container[i].x < 0 && container[i].y < 0){
            sea_num++;
        }
        else if(container[i].x == 0 && container[i].y <= 0){
            coast_num++;
        }
        else if(container[i].x <= 0 && container[i].y == 0){
            coast_num++;
        }
    }
    if(land_num > 0 && sea_num > 0 && coast_num < 1){
        cerr << "Cannot construct MST tree\n";
        exit(1);
    }
}

//run mst
void run_the_mst(vector<Pokemon> &container){
    //initialize
    double total_weight = 0;
    size_t min_index = 0;
	size_t edge_index = 0;
    size_t i = 0;

    //set begin
    container[0].distance = 0;
	container[0].prev = 0;

    //start loop
    while(i < container.size() - 1){
        double weight = 0;
        //initialize min
        double min_weight = numeric_limits<double>::infinity();
        
        //set min index
        min_index = edge_index;
        container[min_index].visited = true;

        //add distance
        total_weight += container[min_index].distance;
		
        //if pokemon at min edge index is land
        if(container[min_index].is_land){
            //find edge end
			for(size_t j = 0; j < container.size(); j++){
                if(!container[j].visited){
                    //if edge end is land/coast
					if(container[j].is_land|| container[j].is_coast){
						weight = find_the_weight(container[min_index], container[j]);
                        //if distance is min, create edge
						if(weight < container[j].distance){
                            container[j].prev = min_index;
							container[j].distance = weight;
						}
					}
                    //if distance of edge end is less than min_weight
                    if(container[j].distance - min_weight < 0){
					    min_weight = container[j].distance;
					    edge_index = j;
                    }
				}
			}
		}
        //if pokemon at min edge index is sea
		else if(container[min_index].is_sea){
			for(size_t j = 0; j < container.size(); j++) {
                if(!container[j].visited){
                    //if edge end is sea/coast
					if(container[j].is_sea || container[j].is_coast){
						weight = find_the_weight(container[min_index], container[j]);
						if(weight < container[j].distance){
                            container[j].prev = min_index;
							container[j].distance = weight; 
						}
                    }
                    if(container[j].distance - min_weight < 0){
					    min_weight = container[j].distance;
                        edge_index = j;
                    }
				}
            }
		}
        //if pokemon at min edge index is coast
		else {
			for(size_t j = 0; j < container.size(); j++){
				if(!container[j].visited){
					weight = find_the_weight(container[min_index], container[j]);
					if(weight < container[j].distance){
                        container[j].prev = min_index;
						container[j].distance = weight;
					}
                    if(container[j].distance - min_weight < 0){
                        min_weight= container[j].distance;
                        edge_index = j;
                    }
				}
			}
		}
    i++;
    }
    //add last edge
    min_index = edge_index;
    total_weight += container[min_index].distance;
    //output
	cout << total_weight << "\n";
    for(size_t i = 1; i < container.size(); i++) {
		cout << min(container[i].id, container[i].prev) << " " << max(container[i].id, container[i].prev) << "\n";
    }
}












////////////

// UTILITIES //////////////////////////////////////////////////////////////////////////////
// euclidean distance
double find_distance(double &ax, double &ay, double &bx, double &by){
    return sqrt((double)pow((bx - ax), 2) + pow((by - ay), 2));
}

// returns weight from two locations
double find_weight(Location &location_a, Location &location_b){
    return find_distance(location_a.x, location_a.y, location_b.x, location_b.y);
}

// INPUT //////////////////////////////////////////////////////////////////////////////////
// process command line
void process_cmd_line(int argc, char** argv, Line_args &line_args){
    std::string spec = "";
    //getopt
    int gotopt;
    int option_index = 0;
    
    static struct option long_opts[] = {
        {"help", no_argument, nullptr, 'h'},
        {"mode", required_argument, nullptr, 'm'},
        {NULL, 0, NULL, 0}
    };
    while((gotopt = getopt_long(argc, argv, "hm:", 
            long_opts, &option_index)) != -1){
        switch(gotopt){
            case 'h':
                print_help();
                exit(0);

            case 'm':
                spec = optarg;
                if(spec == "MST"){
                    line_args.is_mst = true;
                }
                else if(spec == "FASTTSP"){
                    line_args.is_fasttsp = true;
                }
                else if(spec == "OPTTSP"){
                    line_args.is_opttsp = true;
                }
                else if(spec == ""){
                    std::cerr << "Error: No mode specified\n";
                    exit(1);
                }
                else {
                    std::cerr << "Error: Invalid mode\n";
                    exit(1);
                }
                break;
            default:
                std::cerr << "Error: Invalid command line option\n";
                exit(1);
            abort();
        }
    }
}

// get locations
void get_locations(std::vector<Location> &container){
    size_t num = 0;
    std::cin >> num;
    // for num locations, cin location and add to vector
    for(size_t i=0; i < num; i++){
        int x, y;
        std:: cin >> x >> y;
        Location new_location = Location(i, x, y);
        container.push_back(new_location);
    }
}

//print help
void print_help(){
    std::cout << "This program takes a mode parameter in the form of MST, FASTTSP, OPTTSP\n";
}

// FUNCTIONS //////////////////////////////////////////////////////////////////////////////
// PART A
// check mst
// MST cannot be constructed if there are locations in lab and outer, but none in DC
void check_mst(std::vector<Location> &container){
    int lab_num = 0;
    int dc_num = 0;
    int outer_num = 0;
    for(size_t i=0; i < container.size(); i++){
        if(container[i].is_lab()){
            lab_num++;
        }
        else if(container[i].is_dc()){
            dc_num++;
        }
        else if(container[i].is_outer()){
            outer_num++;
        }
    }
    if(lab_num > 0 && outer_num > 0 && dc_num < 1){
        std::cerr << "Cannot construct MST tree\n";
        exit(1);
    }
}

// run mst
void run_mst(std::vector<Location> &container){
    // initialize
    double total_weight = 0;
    size_t min_index = 0;
    size_t edge_index = 0;
    size_t i = 0;
    
    // set beginning
    container[0].distance = 0;
    container[0].prev = 0;

    // start loop
    while(i < container.size() - 1){
        // initialize weight values
        double weight = 0;
        double min_weight = std::numeric_limits<double>::infinity();
        
        // set min index
        min_index = edge_index;
        container[min_index].visited = true;

        // add distance
        total_weight += container[min_index].distance;

        // if location at min edge index is in 
        if(container[min_index].is_outer()){
            // find edge end
            for(size_t j=0; j < container.size(); j++){
                if(!container[j].visited){
                    // if edge end is outer/dc
                    if(container[j].is_outer() || container[j].is_dc()){
                        weight = find_weight(container[min_index], container[j]);
                        // if distance is min, create edge
                        if(weight < container[j].distance){
                            container[j].prev = min_index;
                            container[j].distance = weight;
                        }
                    }
                    // if distance of edge end is less than min_weight
                    if(container[j].distance - min_weight < 0){
                        min_weight = container[j].distance;
                        edge_index = j;
                    }
                }
            }
        }
        // if location at min_index is lab
        else if(container[min_index].is_lab()){
            for(size_t j=0; j < container.size(); j++){
                if(!container[j].visited){
                    // if edge end is lab/dc
                    if(container[j].is_lab() || container[j].is_dc()){
                        weight = find_weight(container[min_index], container[j]);
                        if(weight < container[j].distance){
                            container[j].prev = min_index;
                            container[j].distance = weight;
                        }
                    }
                    if(container[j].distance - min_weight < 0){
                        min_weight = container[j].distance;
                        edge_index = j;
                    }
                }
            }
        }
        // if location at min_index is dc
        else{
            for(size_t j=0; j < container.size(); j++){
                if(!container[j].visited){
                    weight = find_weight(container[min_index], container[j]);
                    if(weight < container[j].distance){
                        container[j].prev = min_index;
                        container[j].distance = weight;
                    }
                    if(container[j].distance - min_weight < 0){
                        min_weight = container[j].distance;
                        edge_index = j;
                    }
                }
            }
        }
        i++;
    }
    // add last edge
    min_index = edge_index;
    total_weight += container[min_index].distance;
    // output
    std::cout << total_weight << "\n";
    for(size_t i=1; i < container.size(); i++){
        std::cout << std::min(container[i].id, container[i].prev) << " " << std::max(container[i].id, container[i].prev) << "\n";
    }
}