I am implementing a simple version of Prim's algorithm using adjacency list using basic graph implementation idea.Here is my approach for this algorithm-
1.Pick an index.
2.Inside the Prims function,mark the index as visited.
3.If any adjacent vertex is not visited and cost of that vertex is less than mi(which is initialized as INF at the start of the function) then mi stores the cost and parent stores the index.
4.At the last adjacent vertex mi stores the smallest cost and parent stores the smallest cost index.
5.Again call the prims for parent vertex.
6.At last return the total cost.
But the problem in my approach is when I am comparing cost[v] with mi then it gives me an error cause I am comparing int with vector.I have tried using mi as a vector but then it gives me error in result section.My code is given below-
#include<bits/stdc++.h>
using namespace std;
#define mx 10005
#define INF 1000000007
vector<int>graph[mx],cost[mx];
int visited[mx]={0};
int result=0,parent;
int n,e,x,y,w,mi;
int prims(int u)
{
mi=INF;
visited[u]=1;
for(int i=0;i<graph[u].size();++i)
{
int v=graph[u][i];
if(visited[v]==0 and cost[v]<mi)
{
mi=cost[v];
parent=v;
}
if(i==graph[u].size()-1)
{
result+=mi;
prims(parent);
}
}
return result;
}
int main()
{
cin>>n>>e;
for(int i=1;i<=e;++i)
{
cin>>x>>y>>w;
graph[x].push_back(y);
graph[y].push_back(x);
cost[x].push_back(w);
cost[y].push_back(w);
}
int src;cin>>src;
int p=prims(src);
cout<<p<<endl;
return 0;
}
Related
I'm having some trouble getting this implementation of Prim's to track the total weight of the shortest path it finds. The path seems to be correct but I can't figure out where to sum the weights as they are added to the array that stores the paths (since it was written only to store paths used).
I've tried summing pCrawl->weight as each vertex is added to the MST but that seems to be the sum of all the weights on the graph. Same with the values key[].
My question is what can be summed each time a path is added to the MST to reflect the total weight of the MST when all shortest paths have been added.
Here's the code I'm using: http://pastebin.com/TFLGCE0L
The Adjacency List I made: http://pastebin.com/SvgGjEPj
And the map used to create it: Map
The Prim's function looks like this:
// The main function that constructs Minimum Spanning Tree (MST)
// using Prim's algorithm
void PrimMST(struct Graph* graph)
{
int V = graph->V;// Get the number of vertices in graph
int parent[V]; // Array to store constructed MST
int key[V]; // Key values used to pick minimum weight edge in cut
// minHeap represents set E
struct MinHeap* minHeap = createMinHeap(V);
// Initialize min heap with all vertices. Key value of
// all vertices (except 0th vertex) is initially infinite
for (int v = 1; v < V; ++v)
{
parent[v] = -1;
key[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v, key[v]);
minHeap->pos[v] = v;
}
// Make key value of 0th vertex as 0 so that it
// is extracted first
key[0] = 0;
minHeap->array[0] = newMinHeapNode(0, key[0]);
minHeap->pos[0] = 0;
// Initially size of min heap is equal to V
minHeap->size = V;
// In the followin loop, min heap contains all nodes
// not yet added to MST.
while (!isEmpty(minHeap))
{
// Extract the vertex with minimum key value
struct MinHeapNode* minHeapNode = extractMin(minHeap);
int u = minHeapNode->v; // Store the extracted vertex number
// Traverse through all adjacent vertices of u (the extracted
// vertex) and update their key values
struct AdjListNode* pCrawl = graph->array[u].head;
while (pCrawl != NULL)
{
int v = pCrawl->dest;
// If v is not yet included in MST and weight of u-v is
// less than key value of v, then update key value and
// parent of v
if (isInMinHeap(minHeap, v) && pCrawl->weight < key[v])
{
key[v] = pCrawl->weight;
parent[v] = u;
decreaseKey(minHeap, v, key[v]);
}
pCrawl = pCrawl->next;
}
}
The structs used look like this:
// A structure to represent a node in adjacency list
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
// A structure to represent an adjacency liat
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
};
// Structure to represent a min heap node
struct MinHeapNode
{
int v;
int key;
};
// Structure to represent a min heap
struct MinHeap
{
int size; // Number of heap nodes present currently
int capacity; // Capacity of min heap
int *pos; // This is needed for decreaseKey()
struct MinHeapNode **array;
};
I feel like I'm in way over my head in this data structures course, hence trying to use code from the internet to solve this small part of the assignment without fulling understanding :/
Thanks,
Michael
You are doing the right thing. Sum of minimum weights (from Prim's) can be equal to sum of all the weights on the graph. Consider the case when there are 4 nodes in a graph and node 1 is at the center and is connected to nodes 2, 3 and 4 with weights of w. 2, 3 and 4 are not connected among themselves. In this case Prim's weight would come out to be 3*w which is same as total weight. I would suggest you to use few different cases, that would clarify what I'm saying.
Edit:
Here is the issue, you are not updating the sum properly.
This -
weightTotal += pCrawl->weight
should be -
weightTotal += pCrawl->weight - key[v]
The issue is I need to create a random undirected graph to test the benchmark of Dijkstra's algorithm using an array and heap to store vertices. AFAIK a heap implementation shall be faster than an array when running on sparse and average graphs, however when it comes to dense graphs, the heap should became less efficient than an array.
I tried to write code that will produce a graph based on the input - number of vertices and total number of edges (maximum number of edges in undirected graph is n(n-1)/2).
On the entrance I divide the total number of edges by the number of vertices so that I have a const number of edges coming out from every single vertex. The graph is represented by an adjacency list. Here is what I came up with:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <set>
#define MAX 1000
#define MIN 1
class Vertex
{
public:
int Number;
int Distance;
Vertex(void);
Vertex(int, int);
~Vertex(void);
};
Vertex::Vertex(void)
{
Number = 0;
Distance = 0;
}
Vertex::Vertex(int C, int D)
{
Number = C;
Distance = D;
}
Vertex::~Vertex(void)
{
}
int main()
{
int VertexNumber, EdgeNumber;
while(scanf("%d %d", &VertexNumber, &EdgeNumber) > 0)
{
int EdgesFromVertex = (EdgeNumber/VertexNumber);
std::list<Vertex>* Graph = new std::list<Vertex> [VertexNumber];
srand(time(NULL));
int Distance, Neighbour;
bool Exist, First;
std::set<std::pair<int, int>> Added;
for(int i = 0; i < VertexNumber; i++)
{
for(int j = 0; j < EdgesFromVertex; j++)
{
First = true;
Exist = true;
while(First || Exist)
{
Neighbour = rand() % (VertexNumber - 1) + 0;
if(!Added.count(std::pair<int, int>(i, Neighbour)))
{
Added.insert(std::pair<int, int>(i, Neighbour));
Exist = false;
}
First = false;
}
}
First = true;
std::set<std::pair<int, int>>::iterator next = Added.begin();
for(std::set<std::pair<int, int>>::iterator it = Added.begin(); it != Added.end();)
{
if(!First)
Added.erase(next);
Distance = rand() % MAX + MIN;
Graph[it->first].push_back(Vertex(it->second, Distance));
Graph[it->second].push_back(Vertex(it->first, Distance));
std::set<std::pair<int, int>>::iterator next = it;
First = false;
}
}
// Dijkstra's implementation
}
return 0;
}
I get an error:
set iterator not dereferencable" when trying to create graph from set data.
I know it has something to do with erasing set elements on the fly, however I need to erase them asap to diminish memory usage.
Maybe there's a better way to create some undirectioned graph? Mine is pretty raw, but that's the best I came up with. I was thinking about making a directed graph which is easier task, but it doesn't ensure that every two vertices will be connected.
I would be grateful for any tips and solutions!
Piotry had basically the same idea I did, but he left off a step.
Only read half the matrix, and ignore you diagonal for writing values to. If you always want a node to have an edge to itself, add a one at the diagonal. If you always do not want a node to have an edge to itself, leave it as a zero.
You can read the other half of your matrix for a second graph for testing your implementation.
Look at the description of std::set::erase :
Iterator validity
Iterators, pointers and references referring to elements removed by
the function are invalidated.
All other iterators, pointers and
references keep their validity.
In your code, if next is equal to it, and you erase element of std::set by next, you can't use it. In this case you must (at least) change it and only after this keep using of it.
QUESTION EDITED, now I only want to know if a queue can be used to improve the algorithm.
I have found this implementation of a mix cost max flow algorithm, which uses dijkstra: http://www.stanford.edu/~liszt90/acm/notebook.html#file2
Gonna paste it here in case it gets lost in the internet void:
// Implementation of min cost max flow algorithm using adjacency
// matrix (Edmonds and Karp 1972). This implementation keeps track of
// forward and reverse edges separately (so you can set cap[i][j] !=
// cap[j][i]). For a regular max flow, set all edge costs to 0.
//
// Running time, O(|V|^2) cost per augmentation
// max flow: O(|V|^3) augmentations
// min cost max flow: O(|V|^4 * MAX_EDGE_COST) augmentations
//
// INPUT:
// - graph, constructed using AddEdge()
// - source
// - sink
//
// OUTPUT:
// - (maximum flow value, minimum cost value)
// - To obtain the actual flow, look at positive values only.
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef long long L;
typedef vector<L> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;
typedef vector<PII> VPII;
const L INF = numeric_limits<L>::max() / 4;
struct MinCostMaxFlow {
int N;
VVL cap, flow, cost;
VI found;
VL dist, pi, width;
VPII dad;
MinCostMaxFlow(int N) :
N(N), cap(N, VL(N)), flow(N, VL(N)), cost(N, VL(N)),
found(N), dist(N), pi(N), width(N), dad(N) {}
void AddEdge(int from, int to, L cap, L cost) {
this->cap[from][to] = cap;
this->cost[from][to] = cost;
}
void Relax(int s, int k, L cap, L cost, int dir) {
L val = dist[s] + pi[s] - pi[k] + cost;
if (cap && val < dist[k]) {
dist[k] = val;
dad[k] = make_pair(s, dir);
width[k] = min(cap, width[s]);
}
}
L Dijkstra(int s, int t) {
fill(found.begin(), found.end(), false);
fill(dist.begin(), dist.end(), INF);
fill(width.begin(), width.end(), 0);
dist[s] = 0;
width[s] = INF;
while (s != -1) {
int best = -1;
found[s] = true;
for (int k = 0; k < N; k++) {
if (found[k]) continue;
Relax(s, k, cap[s][k] - flow[s][k], cost[s][k], 1);
Relax(s, k, flow[k][s], -cost[k][s], -1);
if (best == -1 || dist[k] < dist[best]) best = k;
}
s = best;
}
for (int k = 0; k < N; k++)
pi[k] = min(pi[k] + dist[k], INF);
return width[t];
}
pair<L, L> GetMaxFlow(int s, int t) {
L totflow = 0, totcost = 0;
while (L amt = Dijkstra(s, t)) {
totflow += amt;
for (int x = t; x != s; x = dad[x].first) {
if (dad[x].second == 1) {
flow[dad[x].first][x] += amt;
totcost += amt * cost[dad[x].first][x];
} else {
flow[x][dad[x].first] -= amt;
totcost -= amt * cost[x][dad[x].first];
}
}
}
return make_pair(totflow, totcost);
}
};
My question is if it can be improved by using a priority queue inside of Dijkstra(). I tried but I couldn't get it to work properly.
Actually I suspect that in Dijkstra it should be looping over adjacent nodes, not all nodes...
Thanks a lot.
Surely Dijkstra's algorithm can be improved by using minheap. After we put a vertex into shortest-path tree and process (i.e. label) all adjacent vertices, our next step is to select the vertex with smallest label, not yet in the tree.
This is where minheap comes to mind. Rather than sequentially scan through all vertices, we extract the min element from heap and restructure it, which takes O(logn) time vs O(n). Note that the heap is going to keep only those vertices that are not yet in the shortest-path tree. However we should be able to somehow modify vertices in the heap, if we update their labels.
I am not so sure using a priority queue to implement Dijkstra's algorithm will actually improve the run time because, while using a priority queue decreases the amount of time needed to find the vertex with minimum distance from the source (O(log V) with a priority queue vs. O(V) in the naive implementation), it also increases the amount of time needed to process a new edge (O(log V) with a priority queue vs. O(1) in the naive implementation).
Thus, for the naive implementation, the running time is O(V^2+E).
However, for the priority queue implementation, the running time is O(V log V+E log V).
For very dense graphs, E could be O(V^2), which means the naive implementation would have running time O(V^2+V^2)=O(V^2) while the priority queue implementation would have running time O(V log V+V^2 log V)=O(V^2 log V). Thus, as you can see, the priority queue implementation actually has a worse worst-case run time in the case of dense graphs.
Given the fact that the people writing the above implementation stored the edges as an adjacency matrix rather than using adjacency lists, it looks like the people who wrote this code were expecting the graph to be a dense graph with O(V^2) edges, so it makes sense that they would use the naive implementation over the priority queue implementation here.
For more info about running time of Dijkstra's algorithm, read up on this Wikipedia page.
I'm doing the calculation of the critical path for the DAG of the image, according to this algorithm for another post.My teacher requires that aarray be implemented, I simplify the homework statement, a simple graph implemented through arrays.
This es my code in which I have 3 arrays v, u and d, representing the origin node of the edges, the end node of the edges and the distance between each pair of vertices, as shown in the picture above. in the graph of the image, the duration of the project is equal to 25 corresponding to the sum of distances from the critical path.
My code fails to make good the calculation of distances according to the pseudocode of this link
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
int main (){
int numberVertex=6; //number of vertex
int numberActivities=9;//number of edges
int i, j;
/*vertices are of the form (v, u) */
//indegree of each vertex (that is, count the number of edges entering them)
int indegree [6]={0,0,0,0,0,0};
int v[9]={0,0,1,1,2,4,3,3,3};//array v represent the starting vertex of de edge
int u[9]={1,2,2,3,4,5,4,5,5};//array u represent the coming vertex of de edge
int d[9]={5,6,3,8,2,12,0,1,4};//array d represent the time of de activity (v,u)
int project_duration=0;//project duration
/*# Compute the indegree for each vertex v from the graph:
for each neighbor u of v: indegree[u] += 1*/
for (j=0; j<numberActivities; j++){
indegree[u[j]]++;
}
for (j=0;j<numberVertex; j++)
printf ("indegree %d= %d\n",j,indegree[j] );
queue<int> Q; //queue Q = empty queue
int distance [numberVertex];
memset(distance, 0, sizeof(int) * numberVertex);//distance = array filled with zeroes
//for each vertex v:
//if indegree[v] = 0:
//insert v on Q
for (j=0; j<numberVertex; j++)
{
if (indegree[j]==0)
Q.push(v[j]);
}
int first;
//printf ("first in the queue=%d\n", Q.front());
/*for each neighbor u of v:
d istance[u] = max(distance[u], distance[v] + time(v, u))
indegree[u] -= 1
if indegree[u] = 0:
insert u on Q
*/
while (!Q.empty()){ //while Q is not empty:
first= Q.front (); //v = get front element from Q
Q.pop(); //delete de first from queue
distance[u[first]]=std::max(distance[u[first]],
distance[v[first]]+ d[first]);
indegree[u[first]]-=1;
if (indegree[u[first]]==0){
Q.push(u[first]);
}
}
for (j=0; j<numberVertex; j++)
{
printf ("dist [%d]= %d\n", j, distance[j]);
}
/*Now, select the vertex x with the largest distance.
This is the minimum total project_duration.*/
printf ("Total Project Duration %d\n", project_duration);
return (0);
}
What am I doing wrong or how it could solve the code to tell me what is the duration of the project (corresponds to the sum of distances from the critical path)?. only able to calculate the distance to the first 3 vertex.
Your queue contains vertices. Your arrays u, v, d, are indexed by edge numbers.
So you cannot write
first = Q.front();
... u[first] ...
since first is a vertex.
More generally, your code will be a lot easier to read (and the bug will be more obvious) if you use meaningful variable names. first is not very explicit (first what?), and u, v, d are also quite cryptic.
writing something like
cur_vertex = todo.front()
distance[dest[cur_vertex]] = std::max(distance[dest[cur_vertex]],
distance[source[cur_vertex]]+ weight[cur_vertex]);
will immediately raise a question: the source of a vertex, what is that?
(Here we are using variable names as a substitute for proper type checking. An ADA programmer would have declared two different integer types to avoid the confusion between vertices and edge numbers.)
Another question: where did the loop over the successors of first go? It's in the pseudo-code, but not in your source.
This is the dijkstra structure i am using :(however the MAXV(which is maximum number of vertices is maximum at 500 and every time i try to change it to something more than this it generates and error when running )
-I want to use this way to represent a graph with 10000 vertices, does anyone know how to optimize it ?
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
using namespace std;
#define MAXV 500
#define MAXINT 99999
typedef struct{
int next;
int weight;
}edge;
typedef struct{
edge edges[MAXV][MAXV];
int nedges;
int nvertices;
int ndegree[MAXV];
}graph;
and this is my dijkstra code:
int dijkstra(graph *g,int start,int end){
int distance[MAXV];
bool intree[MAXV];
for(int i=0;i<=MAXV;++i){
intree[i]=false;
distance[i]=MAXINT;
}
int v=start;
distance[v]=0;
while(intree[v]==false){
intree[v]=true;
for(int i=0;i<g->ndegree[v];++i){
int cand=g->edges[v][i].next;
int weight=g->edges[v][i].weight;
if(distance[cand] > distance[v]+weight){
distance[cand] = distance[v]+weight;
}
}
int dist=MAXINT;
for(int i=0;i<g->nvertices;++i){
if((intree[i]==false) && (dist > distance[i])){
dist=distance[i];
v=i;
}
}
}
return distance[end];
}
Use adjacency lists for storing the graph. Right now you're using an adjacency matrix, which means that you allocate MAXV*MAXV*sizeof(edge) bytes just for that. That's a lot when MAXV is 10 000, so you're probably getting a segmentation fault. Switching to adjacency lists will get rid of the error.
However, even with adjacency lists, the Dijkstra algorithm you have right now is O(n^2) where n is the number of nodes. That's still a lot for 10 000 nodes. Consider implementing Dijkstra with heaps (also here) if you have to support this many nodes.