How to fix a directed graph on undirected? - c++

I can not correctly correct the code so that the graph was undirected. By input, by condition, there should be a number of vertices, edges and then a list of adjacent vertices and their weight
using namespace std;
const int inf = 10000000;
struct edge {
int u, v, w;
};
int n, m, v, i;
vector<edge> e;
void solve() {
vector<int> d(n, inf);
d[v] = 0;
for (;;) {
bool any = false;
for (int j = 0; j < m; ++j)
if (d[e[j].u] < inf)
if (d[e[j].v] > d[e[j].u] + e[j].w) {
d[e[j].v] = d[e[j].u] + e[j].w;
any = true;
}
if (!any) break;
}
cout << d[d.size()-1] << endl;
}
int main() {
cin >> n >> m;
edge t;
for (i = 0; i<m; i++)
{
cin >> t.u >> t.v >> t.w;
t.u--; t.v--;
e.push_back(t);
}
solve();
}

From mathematical point of view an undirected graph should be equivalent to a directed one if you substitute every undirected edge with a pair of directed edges with opposite directions.
As far as I can see, you are trying to implement the Bellman-Ford algorithm. Some notes regarding your implementation. As I can see, your v global variable is not initialized properly. Is that intentional to assume that the source is the vertex with the index 0? Bellman-Ford finds the shortest paths from the source to all other vertices; you output the length of the path to the vertex with the maximum index, is that what you expect?
One major issue: what would happen if you have a negative cycle (that is possible, as you use signed int for storing the weights)? The benefit of the Bellman-Ford algorithm is that it works correctly if some of the graph's edges have negative weights. Moreover, it allows you to detect the presence of negative cycles, but in your case the algorithm would get into an infinite loop. The solution is to limit the number of iterations with n; if on the n-th iteration you find that you still haven't left the loop, there is an negative cycle in your graph.

Related

Finding a path in a graph with random edges

We have n vertices (where n is less than 100 000) and m random edges (where m is less than 10 000 000). We want to find a path between 2 given vertices. If there is no path we will just print -1.
My algorithm is to build a tree. Every vertex has a disjoint_index (i) which shows that all vertices with disjoint_index (i), are connected.
The default value of disjoint_index is the index of each vertex. After finding an edge between vertex v and u, I check if they are connected. If they are connected, I do nothing. Else I change the disjoint_index of u and all the vertices connected to u by a function named (dfs).
Here is the code of the function to build this tree in c++:
struct vertex{
int disjoint_index;
vector<int> adjacent;
};
void build_tree(int m, int s, int e)
{
for(int i = 0; i < m; i++)
{
int u = kiss() % n;
int v = kiss() % n;
if(disjoint_counter[u] > disjoint_counter[v])
{
int temp = u;
u = v;
v = temp;
}//counter v > u
if(ver[v].disjoint_index != ver[u].disjoint_index)
{
ver[v].adjacent.push_back(u);
ver[u].adjacent.push_back(v);
dfs(v, u, ver[v].disjoint_index);
disjoint_counter[v] += disjoint_counter[u];
}
if(ver[s].disjoint_index == ver[e].disjoint_index)
return;
}
}
void dfs(int parent, int v, int d)
{
ver[v].disjoint_index = d;
for(int i = 0; i < ver[v].adjacent.size(); i++)
{
if(ver[v].adjacent[i] == parent)
continue;
dfs(v, ver[v].adjacent[i], d);
}
}
Here you can skip kiss, It's just a function that returns two vertices and shows that there is an edge between u and v.
disjoint_counter[i] shows how many vertices are in connected group i.
After building this tree I will find a path with a simple dfs. The time limit is 1s and I get Time Limit Exceeded on some test cases.
Edit: Memory is limited so I can't save all the edges.
Maximum memory I can use is 32MB.
I used the disjoint set union algorithm, it developed speed.

Finding the number of connected components in an undirected graph

Source:
here
Problem:
Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph.
Approach:
class Solution
{
public:
int countComponents(int n, vector<vector<int>>& edges)
{
std::vector<bool> v(n, false);
int count = 0;
for(int i = 0; i < n; ++i)
{
if(!v[i])
{
dfs(edges, v, i);
count++;
}
}
return count;
}
void dfs(std::vector<std::vector<int>>& edges, std::vector<bool>& v, int i)
{
if(v[i] || i > edges.size())
return;
v[i] = true;
for(int j = 0; j < edges[i].size(); ++j)
dfs(edges, v, edges[i][j]);
}
};
Error:
heap-buffer overflow
I am not understanding why my code is causing a heap-buffer overflow for the test case:
5
[[0,1],[1,2],[2,3],[3,4]]
Any suggestions on how to fix my code would be really appreciated.
My guess is that your edges vector has only four elements in it for the provided input, since there is no outgoing edge from vertex 4. Your dfs function then eventually recurs into the point where i == 4, but your edges vector has only 4 elements, thus the last valid possition is edges[3].
I suggest that you represent a vertex with no outgoing vertices with an empty vector.
Also, the second part of the if statement
if(v[i] || i > edges.size())
return;
seems unecceserry and should probably just be
if(v[i])
return;

paths between two nodes in a directed graph with parallel edges

Given a directed graph with parallel edges, I need to find the number of paths between the first and the last node in the input. Traversal of the same edge multiple times is allowed and parallel edges count as distinct paths.
The way I approached the problem is considering the number of paths between node s and node t that are no longer than k. The longest simple path in a graph with N nodes has N-1 vertices, thus if there are no cycles, path_count(s,t,n-1) and path_count(s,t,3n-3) should be equal. 3n -3 is basically a traversal of the longest simple path, a second traversal to the origin and yet another one to the target, establishing a cycle by reaching the target twice.
I have written some code to implement this. I use a vector called lookup to store intermediate results to speed things up. Here's what I've come up with:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
vector<vector<int>> lookup;
int paths_count(vector<vector<int>> & graph, int k, int start, int dest)
{
if (lookup[k][start] != -1)
return lookup[k][start];
int result =0;
if (k==1 && graph[start][dest]) //last hop, ends on target vertex
{
lookup[k][start] = graph[start][dest];
return graph[start][dest];
}
if (k==1) { // last hop, didn't reach target vertex
lookup[k][start]=0;
return 0;
}
for (int i=1; i < graph.size(); i++) {
if (graph[start][i]>0) {
if (i==dest) // assume no outbound edges from destination vertex
result+=graph[start][dest];
else {
// paths from i to dest
int pc =paths_count(graph, k-1, i, dest);
/*
total number of paths from start to dest through i is the
number of paths from i to dest
times the number of edges from start to i
*/
result+=graph[start][i]*pc;
}
}
}
lookup[k][start]=result;
return result;
}
int main() {
int n, m,x,y;
vector<vector<int>> graph;
cin >> n >>m;
graph.resize(n+1);
lookup.resize(3*n - 2);
for (int i=0; i < 3*n-2;++i)
for (int j=0; j < n+1;++j)
lookup[i].push_back(-1);
for (int i=0; i < n+1; ++i)
graph[i].resize(n+1);
for (int i=0; i <m;++i) {
cin >> x >>y;
graph[x][y]+=1;
}
int count1 = paths_count(graph,n-1,1,n);
int count2 = paths_count(graph,3*n-3,1,n);
if (count1 != count2)
cout << "INFINITE PATHS";
else
cout << count1;
return 0;
}
the issue is that I have some given test cases, and some test cases I've written myself. My solution succeeds on my test cases and on some small-ish test cases but fails on the larges ones which I cannot manually debug (100 nodes, thousands of vertices). I've also tried a different idea with DFS that failed on the same test cases, leading me to believe that I fundamentally don't understand something about this problem. Any ideas?
Thank you.

How to represent a graph in c++

I would like to write prims and dijkstra algoritms that create a MST. But I do not know what is the best way to represent graph in c++.
I could represent an edge by pair of two ints for example vector 0 to 1 would be pair(0,1);
typedef pair<int, int> Edge;
And then the prims function would take Vector of pairs that consist of an edge and its weight.
void prims(vector<pair<Edge, int>>);
I think that this way is not the best one, could anyone tell me what way would be the best to represent a graph?
I have been implementing Dijkstra some time ago for finding paths in binary images. I represented a graph as a vector of a struct GraphNodes that contained a vector of Connections that contained all the connections of the node to other nodes. Each connection has its distance attribute, which is the weight of the edge. Here are the two structs I used:
//forward declaration
struct GraphNode;
struct Connection {
Connection() : distance(1) { };
Connection(GraphNode* ptr, double distance) : ptr(ptr), distance(distance) { };
bool operator==(const Connection &other) const;
GraphNode* ptr;
double distance;
};
struct GraphNode {
GraphNode() : connections(8), predecessor(NULL), distance(-1) { };
cv::Point point;
double distance;
GraphNode* predecessor;
std::vector<Connection> connections;
};
bool Connection::operator==(const Connection &other) const {
return ptr == other.ptr && distance == other.distance;
}
The distance attribute of the GraphNode is the distance it currently has in the Dijkstra algorithm, so the distance of the shortest currently known distance to the start node. At the beginning this is initialized with -1.
I then implemented the Dijkstra algorithm like this:
std::vector<cv::Point> findShortestPathDijkstra(std::vector<GraphNode>& graph, int startNodeIndex, int destNodeIndex) const {
GraphDistanceSorter sorter(graph);
std::set<GraphNode*, GraphDistanceSorter> unusedNodes(sorter);
for (int i = 0; i < graph.size(); ++i) {
unusedNodes.insert(&graph[i]);
}
while (unusedNodes.size() > 0) {
GraphNode* currentNode = *unusedNodes.begin();
if (currentNode->distance == -1) {
return std::vector<cv::Point>();
}
if (currentNode == &graph[destNodeIndex]) break;
unusedNodes.erase(currentNode);
//update distances of connected nodes
for (Connection const& con : currentNode->connections) {
/*here we could check if the element is really in unusedNodes (search, O(log n)), but this would
actually take longer than calculating the new distance (O(1)), which will in this case always be greater
than the old one, so the distance is never updated for nodes not in unusedNodes ()*/
double newDistance = currentNode->distance + con.distance;
if (newDistance < con.ptr->distance || con.ptr->distance == -1) {
unusedNodes.erase(con.ptr);
con.ptr->distance = newDistance;
con.ptr->predecessor = currentNode;
unusedNodes.insert(con.ptr);
}
}
}
//now trace back the path as a list of points
std::vector<cv::Point> points;
GraphNode* current = &graph[destNodeIndex];
points.push_back(current->point);
while (current != &graph[startNodeIndex]) {
if (current->predecessor == NULL) return std::vector<cv::Point>();
current = current->predecessor;
points.push_back(current->point);
}
return points;
}
As you see there is a set unusedNodes that contains all the unused nodes so far. It only contains pointers on graphNodes. The actual graph representation is in the vector. The advantage of having a set is, that it is always sorted according to a certain criterion. I implemented my own sorter GraphDistanceSorter that sorts the GraphNodes according to the distance criterion of the Dijkstra algorithm. This way I just have to pick the first node from the set and know that it's the one with the smallest distance:
struct GraphDistanceSorter {
bool operator() (const GraphNode* lhs, const GraphNode* rhs) const;
};
bool GraphDistanceSorter::operator() (const GraphNode* lhs, const GraphNode* rhs) const {
if (lhs->distance == rhs->distance) {
return lhs < rhs;
} else {
if (lhs->distance != -1 && rhs->distance != -1) {
if (lhs->distance != rhs->distance) {
return lhs->distance < rhs->distance;
}
} else if (lhs->distance != -1 && rhs->distance == -1) {
return true;
}
return false;
}
}
The two main ways to represent graphs learned in theoretical computer-science are adjacency matrix and adjacency lists.
Adjacency Matrix is as shown in the photo below is an n*n matrix and a[i][j] represents the edge between node i and node j so if it's a weighted graph it can be an integer instead of a boolean value for unweighted graphs.
adjacency matrix (photo source: google)
On the other hand, adjacency lists is a set of linked-lists (n-set to be exact), the i-th set has exactly the nodes i is connected to.
in this case you will need some additional way to save edge distance for example you can build your own class Edge as following
class Edge
{
int destination, length;
Edge* next = 0;
}
and use it for your linked-list. How ever I am used to std::vector<std::pair<int, int>> a[N] to define a list of pairs and a[i][j].first would be the j-th neighbor of nod i and a[i][j].second the length of the edge between them.
For undirected graph your can add i to j neighbors as well.
So it's also a flexible way to represent graphs.
adjacency lists (image source: google photos)
So now let's talk complexity, I will try to keep it as simple as possible:
We habe n lists, each has the #(edges going out of node i)
so the total number is sum of this numbers which is the total number of edges E.
That means place complexity is O(E) which is at most 5 * n in a sparse-graph in comparison to O(N^2) in adjacency matrix. (We need a linear factor of E to represent it).
Now let's consider visiting all neighbors of a nod x:
in adjacency matrix we will go through the whole x-th line and if it's not 0 there's an edge there which is O(N).
In adjacency lists it's again exactly the number of neighbors of x which can though reach O(N).
But if we are visiting all neighbors of all Nodes (which is the case in Dijkstra when updating dis array), you will need to visit n elements n times in adjacency lists which is also O(N^2) time complexity while in adjacency lists it's exactly the sum of the number of neighbors - again E. which means we need also O(E) to visit all neighbors of all edges.
And sind all edges are given usually in the input O(E) would pass as calculation time, but O(N^2) would be a high complexity for constraints of N <= 10^6 for example.
At the end I will leave you with my usual implementation of diffreent variants of graphs using adjacency lists (vector as a list):
#include<iostream>
#include<vector>
int main(){
const int N = 5;
int n, e;
std::vector<std::pair<int, int>> graph[N], inverse[N];
std::vector<int> unweighted[N], undirectedUnweighted[N];
std::cin >> n >> e;
for(int i = 0; i < e; i++)
{
int x, y, z;//z is length of edge
std::cin >> x >> y >> z;
//substitute 1 from x, y if they starts from 1
graph[x].push_back(std::make_pair(y, z));
inverse[y].push_back(std::make_pair(x, z));
unweighted[x].push_back(y);
undirectedUnweighted[x].push_back(y);
undirectedUnweighted[y].push_back(x);
}
return 0;
}
Simple form for representing graph (finding neighbors and degrees for vertices)
#include<iostream>
/** Representing graphs in c++ programming language */
using namespace std;
int main() {
cout << "\033[1;33mNote: if there are no neighbourhood between vertices write '-' symbol!\033[0m\n"<<endl;
int number_of_vertices;
cout<<"\033[1;32mPlease enter number of vertices: \033[0m";
cin>>number_of_vertices;
int max_num_of_neighbours;
cout<<"\033[1;32mPlease enter maximum number of neighbours: \033[0m";
cin>>max_num_of_neighbours;
char array[number_of_vertices][max_num_of_neighbours];
char vertices[number_of_vertices];
cout<<"\033[1;33mPlease sign vertices with lowercase alphabet letters: \033[0m"<<endl;
for(int i = 0; i < number_of_vertices; i ++) {
cout<<(i+1)<<" = ";
cin>>vertices[i];
}
for(int i = 0; i < number_of_vertices; cout<<endl, i ++) {
cout<<"\033[1;32mPlease enter neighbours for \033[0m"<<vertices[i]<<" --> ";
for(int j = 0; j < max_num_of_neighbours; j ++) {
cin>>array[i][j];
}
}
for(int i = 0; i < number_of_vertices; cout<<endl, i ++) {
cout<<"\033[1;34mNeighbours for \033[0m"<<"\033[1;35m"<<vertices[i]<<"\033[0m"<<" --> ";
int deg = 0;
for(int j = 0; j < max_num_of_neighbours; j ++) {
if(array[i][j] != '-') {
deg ++;
}
if(array[i][j] == '-') {
cout<<"\033[1;31m"<<array[i][j]<<"\033[0m"<<"\t";
} else {
cout<<"\033[1;32m"<<array[i][j]<<"\033[0m"<<"\t";
}
}
cout<<"\033[1;36m"<<"deg["<<"\033[0m"<<"\033[1;35m"<<vertices[i]<<"\033[0m"<<"\033[1;36m"<<"] = "<<"\033[0m"<<deg;
}
cout<<endl<<"\033[1;33mRemember that '\033[1;31m-\033[0m\033[1;33m' shows when two vertices aren't adjacent!\033[0m"<<endl;
}
For adding interactivity I used How do I output coloured text to a Linux terminal? for changing color of text

Generating random Graph

Have someone input an integer N as the number of vertices in the graph.
Assign random weights on each edges ranging from 1 to 10. Not all possible edges
are present though! As in the above example, represented an absent edge by an X.
Return a pair (M,L), with M and L respectively being the matrix and list representation
of the (same) random graph you are generating.
Use non-digit characters as vertex names, to avoid confusion with edge weights.
#include <iostream>
#include <stdlib.h>
using namespace std;
void gen_random_graph(int n)
{
int adj_matrix[n][n];
for(int u = 0; u < n; u++)
{
for (int v = 0; v < n; v++)
{
if(adj_matrix[u][v]==adj_matrix[v][u])
{
adj_matrix[u][v] = rand() % 10 + 1;
cout << adj_matrix[u][v] << endl;
}
}
}
}
int main()
{
int N;
cout << "enter number of vertices" << endl;
cin >> N;
gen_random_graph(N);
return 0;
}
THis is my code so far. Is it generateing the weights ? and what does it mean i have to return a pair?
A graph can be represented as an N x N adjacency matrix (as you have already set up), where the value in matrix[i][j] corresponds to the weight of the edge connecting vertex i to vertex j. A zero corresponds to there not being a connection between i and j. If matrix[i][j] == matrix[j][i], then you have an undirected graph. Furthermore, a random graph would have random values as the edges between vertices.
In the case where every edge either exists or doesn't exist (i.e. weights are either 0 or 1), you could have the following:
This image is stolen from the internet, so I take no credit for it. Note that you can easily confirm that the first graph is undirected because the adjacency matrix is symmetric. Likewise, the second graph is directed because the matrix is NOT symmetric.