#include #include #include #include #include #include using namespace std; struct ADMATRIX { vector < vector > MATRIX; }; ADMATRIX* readFile(string input_file); void TSP_BackTracking(ADMATRIX* matrix, vector& check, int currentPosition, int n, int count, int weight, int& ans, vector& path, vector& ans_path); void printTSP(string input_file); // ReadFile function of MINH DUNG ADMATRIX* readFile(string input_file) { // Declare variables ADMATRIX* a = new ADMATRIX; string readLine, token; //Open file to read the data ifstream fin(input_file); if (fin.fail()) { cout << "Cannot open file" << endl; } else { // 1st line: n cities getline(fin, readLine); int n = stoi(readLine); // Initialize the matrix with n vertices vector temp; for (int i = 0; i < n; i++) temp.push_back(0); for (int i = 0; i < n; i++) a->MATRIX.push_back(temp); //Other lines: CityA CityB Distance while (getline(fin, readLine)) { vector temp2; istringstream ss(readLine); while (getline(ss, token, ' ')) { temp2.push_back(stoi(token)); } // IMPORTANT: because cities are marked from 1 to n // e.g. if we read 1 2 10 // we will save as 0 1 10 if (temp2[0] <= n && temp2[1] <= n) { a->MATRIX[temp2[0] - 1][temp2[1] - 1] = temp2[2]; a->MATRIX[temp2[1] - 1][temp2[0] - 1] = temp2[2]; } } } fin.close(); return a; } // By MINH DUNG bool isHamiltonPath(ADMATRIX* a, int v, vector visited, vector path) { // If all vertices are visited, then Hamilton path exists if (path.size() == a->MATRIX.size()) return true; // Check if every edge starting from vertex v leads to a solution or not for (int w = 0; w < a->MATRIX.size(); w++) { // process only unvisited vertices as Hamiltonian // path visits each vertex exactly once if (!visited[w] && a->MATRIX[v][w] != 0) { visited[w] = true; path.push_back(w); // check if adding vertex w to the path leads // to solution or not if (isHamiltonPath(a, w, visited, path)) { return true; } // Backtrack visited[w] = false; path.pop_back(); } } return false; } void printHPath(string input_file) { // Read matrix from file ADMATRIX* a = readFile(input_file); // Add starting node to the path vector path; path.push_back(0); // Mark starting node as visited vector visited; for (int i = 0; i < a->MATRIX.size(); i++) { visited.push_back(false); } // Check Hamilton path for (int i = 0; i < a->MATRIX.size(); i++) { visited[i] = true; if (isHamiltonPath(a, i, visited, path)) { cout << "YES" << endl; return; } visited[i] = false; } cout << "NO" << endl; } // By BAO HAN bool isSafe(int v, ADMATRIX* a, int path[], int pos) { // Check if it is a graph between the last vertex in Hamilton cycle and this vertex if (a->MATRIX[path[pos - 1]][v] == 0) return false; // Check if this vertex has already been included for (int i = 0; i < pos; i++) if (path[i] == v) return false; return true; } // 'pos' is the number of vertices we have added to Hamilton cycle bool findHamiltonCycle(int n, ADMATRIX* a, int* path, int pos) { // If all vertices are in Hamilton cycle // and the last vertex connect to the first, return true, otherwise return false if (pos == n) { if (a->MATRIX[path[pos - 1]][path[0]] != 0) return true; else return false; } // Try all vertices (except 0-the initial vertex) as a next candidate in Hamilton cycle for (int v = 1; v < n; v++) { // Check if vertex can be add to Hamilton cycle if (isSafe(v, a, path, pos)) { path[pos] = v; // Recursive to construct rest of the path if (findHamiltonCycle(n, a, path, pos + 1) == true) return true; // If this vertex doesn't lead to any solution, then remove it path[pos] = -1; } } // Can't find the path return false; } bool isHamiltonCycle(ADMATRIX* a) { int n = a->MATRIX.size(); // 'path' stores the vertices of Hamilton cycle int* path = new int[n]; for (int i = 0; i < n; i++) path[i] = -1; // Initialize by the vertex 0 path[0] = 0; // Find Hamilton cycle if (findHamiltonCycle(n, a, path, 1) == false) return false; else return true; } void printHCycle(string input_file) { // Read matrix from file ADMATRIX* a = readFile(input_file); if (isHamiltonCycle(a)) cout << "YES\n"; else cout << "NO\n"; } // By KY LUONG // Using BackTracking to find the minimun weight of Hamiltonian Cycle void TSP_BackTracking(ADMATRIX* matrix, vector& check, int currentPosition, int n, int count, int weight, int& ans, vector& path, vector& ans_path) { // BASE CASE: // If we have traversed all the node of the graph. Keep the minimum weight and the path // Finally return to check for more possible values if (count == n && matrix->MATRIX[currentPosition][0]) { if (ans > weight + matrix->MATRIX[currentPosition][0]) { ans_path = path; } ans = min(ans, weight + matrix->MATRIX[currentPosition][0]); return; } // BACKTRACKING STEP: // Loop to traverse the adjacency list of currentPosition node and increasing the count by 1 and cost by graph[currentPosition][i] value for (int i = 0; i < n; i++) { if (!check[i] && matrix->MATRIX[currentPosition][i]) { // Mark as visited check[i] = true; // Record the path path.push_back(i + 1); //Rescursive Call TSP_BackTracking(matrix, check, i, n, count + 1, weight + matrix->MATRIX[currentPosition][i], ans, path, ans_path); // Mark the node in position i as unvisited check[i] = false; } } } void printTSP(string input_file) { ADMATRIX* matrix = readFile(input_file); int n = matrix->MATRIX.size(); vector check(n); for (int i = 0; i < n; ++i) { check[i] = false; } check[0] = true; int ans = INT_MAX; vector path; // vector that is used to record the path vector ans_path; // vector that is the answer path TSP_BackTracking(matrix, check, 0, n, 1, 0, ans, path, ans_path); if (ans == INT_MAX) // ans is still INT_MAX and not change . Therefore, there is no TSP { cout << "-1" << endl; } else { // We realise that the ans_path in some cases is not the path that we are looking for // The reason is we have recorded some path in backtracking // for example: ans_path is: 2 3 4 5 5 4 4 3 5 5 3 5 3 4 4 3 // Then, the real answer is: 1 2 5 4 3 // We have to traverse from the end to the beginning of the ans_path and Add at the beginning of the // new list if that element is not in the new list yet. Then, add 1 at the beginning. // (2) 3 4 5 5 4 4 3 5 5 3 (5) 3 4 (4) (3) // => 1 2 5 4 3 vector new_list; for (int i = ans_path.size() - 1; i >= 0; --i) { if (find(new_list.begin(), new_list.end(), ans_path[i]) == new_list.end()) { new_list.insert(new_list.begin(), ans_path[i]); } } new_list.insert(new_list.begin(), 1); for (int i = 0; i < new_list.size(); ++i) { cout << new_list[i] << " "; } cout << endl; cout << ans << endl; } delete matrix; } // By NHAT QUANG void output_main(string action, string input_file) { if (action == "-HPath") { printHPath(input_file); } else if (action == "-HCycle") { printHCycle(input_file); } else if (action == "-TSP") { printTSP(input_file); } else cout << "Error func" << endl; } int main(int argc, char* argv[]) { string action, input_file; if (argc > 2) { action = argv[1]; input_file = argv[2]; output_main(action, input_file); } else { cout << "Enter action: "; cin >> action; cout << "Enter input_file: "; cin >> input_file; output_main(action, input_file); } if (!system(NULL)) system("pause"); return 0; }