#include<bits/stdc++.h>
using namespace std;
# define INF 0x3f3f3f3f
/* iPair ==> Integer Pair */
typedef pair<int, int> iPair;
/* This class represents a directed graph using */
/* adjacency list representation */
struct Graph
{
int V; /* No. of vertices */
/* In a weighted graph, we need to store vertex */
/* and weight pair for every edge */
list<iPair> *edges;
Graph(int V)
{
this->V = V;
edges = new list<iPair> [V];
}
/* function to add an edge to graph */
void addEdge(int u, int v, int w)
{
edges[u].push_back(make_pair(v, w));
edges[v].push_back(make_pair(u, w));
}
/* Print MST using Prim's algorithm */
int primMST();
};
/* Prints shortest paths from src to all other vertices */
int Graph::primMST()
{
/* Create a priority queue to store vertices that
are being preinMST. This is weird syntax in C++.
Refer below link for details of this syntax
http://g...content-available-to-author-only...z.com/implement-min-heap-using-stl/ */
priority_queue< iPair, vector <iPair> , greater<iPair> > pq;
int src = 0; // Taking vertex 0 as source*/
/* Create a vector for keys and initialize all
keys as infinite (INF) */
vector<int> key(V, INF);
/* To store parent array which in turn store MST*/
vector<int> parent(V, -1);
/* To keep track of vertices included in MST */
vector<bool> inMST(V, false);
/* Insert source itself in priority queue and initialize
its key as 0. */
pq.push(make_pair(0, src));
key[src] = 0;
/* Looping till priority queue becomes empty */
while (!pq.empty())
{
/* The first vertex in pair is the minimum key
vertex, extract it from priority queue.
vertex label is stored in second of pair (it
has to be done this way to keep the vertices
sorted key (key must be first item
in pair) */
int u = pq.top().second;
pq.pop();
inMST[u] = true; // Include vertex in MST */
/*'i' is used to get all adjacent vertices of a vertex */
list< pair<int, int> >::iterator i;
for (i = edges[u].begin(); i != edges[u].end(); ++i)
{
/* Get vertex label and weight of current adjacent
of u. */
int v = (*i).first;
int weight = (*i).second;
/* If v is not in MST and weight of (u,v) is smaller
than current key of v */
if (inMST[v] == false && key[v] > weight)
{
/*Updating key of v */
key[v] = weight;
pq.push(make_pair(key[v], v));
parent[v] = u;
}
}
}
int total = 0;
/* Print edges of MST using parent array */
for (int i = 1; i < V; ++i) {
for(auto k : edges[i]){
if(k.first == parent[i])
total+=k.second;
}
}
return total;
}
int findPathCost(vector<pair<int,int>> adj[], int u,int v){
for(auto it = adj[u].begin(); it != adj[u].end(); ++it){
if((*it).first == v){
return (*it).second;
}
}
}
int isExistOpen(vector<pair<int,iPair>> open,int v){
for(auto it = open.begin(); it != open.end(); ++it){
if((*it).second.second == v){
return (*it).first;
}
}
}
void findAndUpdate(vector<pair<int,iPair>> &open,int tc, int pc, int v){
for(auto it = open.begin(); it != open.end(); ++it){
if((*it).second.second == v){
(*it).second.first = pc;
(*it).first = tc;
return;
}
}
}
int findMinh1(int *adj[], int v, vector<int> remainEle){
int mini = remainEle.size() > 1 ? INT_MAX : 0;
for(auto it = remainEle.begin(); it != remainEle.end(); ++it){
if(adj[v][*it] < mini && *it != v){
mini = adj[v][*it];
}
}
return mini;
}
int findMinh2(int *adj[], int v, vector<int> remainEle){
int mini = remainEle.size() > 1 ? INT_MAX : 0;
for(auto it = remainEle.begin(); it != remainEle.end(); ++it){
if(adj[0][*it] < mini && *it != v){
mini = adj[0][*it];
}
}
return mini;
}
int heuristicCost(int v, int *adj[], vector<int> remainEle){
int h1, h2, h3;
h1 = findMinh1(adj,v,remainEle);
h2 = findMinh2(adj,v,remainEle);
Graph graph(remainEle.size()-1);
int i = 0, j = 0;
for(auto it = remainEle.begin(); it != remainEle.end(); ++it){
if(*it != v){
j = i+1;
for(auto jt = it+1; jt != remainEle.end(); ++jt){
if(*jt != v){
graph.addEdge(i,j,adj[*it][*jt]);
++j;
}
}
++i;
}
}
h3 = graph.primMST();
return h1+h2+h3;
}
int AStar(int **adj, int V){
vector<pair<int,iPair>> open;
vector<int> closed;
vector<int> remainEle;
for(int i = 0; i < V; ++i)
remainEle.push_back(i);
int hc = heuristicCost(0,adj,remainEle);
hc = heuristicCost(1,adj,remainEle);
hc = heuristicCost(2,adj,remainEle);
int pc = 0;
int tc = hc + pc;
int minPathCost = 0;
open.push_back({tc,{pc,0}});
// while(!remainEle.empty()){
// cout<<"hry";
// auto mini = std::min_element(open.cbegin(), open.cend(), [](const auto& lhs, const auto& rhs) {
// return lhs.first < rhs.first;
// });
// pair<int,iPair> storePair = *mini;
// open.erase(mini);
// int ppc = storePair.second.first;
// int city = storePair.second.second;
// closed.push_back(city);
// remainEle.erase(find(remainEle.begin(),remainEle.end(),city));
// if(remainEle.empty()){
// minPathCost = ppc + adj[0][city];
// }
// for(auto it = remainEle.begin(); it != remainEle.end(); ++it){
// hc = heuristicCost((*it),adj,remainEle);
// pc = ppc + adj[city][*it];
// tc = pc + hc;
// int existTCO = isExistOpen(open,(*it));
// if(existTCO != -1){
// findAndUpdate(open,tc,pc,(*it));
// }
// else{
// open.push_back({tc,{pc,(*it)}});
// }
// }
// }
return hc;
}
/* Driver program to test methods of graph class */
int main()
{
/* create the graph given in above fugure */
int V;
cout << "Enter the no. of cities: ";
cin >> V;
int **adj;
adj = new int *[V];
for(int i = 0; i < V; i++)
adj[i] = new int[V];
cout << "Enter the path cost" << endl;
for(int i = 0; i < V; ++i){
for(int j = 0; j < V; ++j)
cin >> adj[i][j];
}
int minPathCost = AStar(adj,V);
cout << "optimal path cost: " << minPathCost << endl;
return 0;
}