Problem with the implementation of DFS recursively - c++

I have tried to implement DFS on my own recursively, but i have a problem. I can't find where my mistake is. I tried to implement it entirely on my own and I am having a problem. Most implementations of DFS I have seen use OOP and I am trying to implement it simply by list of neighbours with dynamic array.
using namespace std;
void DFS(vector<int> *numNodes, int startingVertex, bool* used) {
for(int i:numNodes[startingVertex]) {
if(!used[i]) {
used[i] = true;
cout<<i<<endl;
DFS(numNodes, i, used);
}
}
}
int main()
{
int n, k, temp, startingVertex;
cin>>n;
vector<int> numNodes[n];
for(int i=0; i<n; i++) {
cout<<"How many neighbours for node "<<i<<"?"<<endl;
cin>>k;
cout<<"Enter neighbours"<<endl;
for(int j=0; j<k; j++) {
cin>>temp;
numNodes[i].push_back(temp);
}
}
cout<<"Enter starting point"<<endl;
bool used[n];
for(int i=0; i<n; i++) {
used[i] = false;
}
cin>>startingVertex;
cout<<"Starting DFS from vertex "<<startingVertex<<"..."<<endl;
cout<<startingVertex<<endl;
used[startingVertex] = true;
DFS(numNodes, startingVertex, used);
}

There's a lot of comments on the ticket about good C++/coding practices, but from an algorithmic standpoint, the issue I'm seeing is that after the recursive call of DFS(numNodes, i, used); you need to set used[i] back to false, so that node i can be used again for another path through the graph.

Related

Adjacency List in graph

Hi I am try to implement a graph using adjacency list using following code.
#include<iostream>
#include<list>
#include<vector>
#include<unordered_map>
using namespace std;
class graph{
public:
vector<int> adj[10000];
void insert(int u,int v, bool direction) {
adj[u].push_back(v);
if(direction==1) {
adj[v].push_back(u);
}
}
void print(int n) {
for(int i=0;i<n+1;i++) {
cout<<i<<"->";
for(auto j : adj[i]) {
cout<<j<<",";
}
cout<<endl;
}
}
};
int main( ) {
int n;
cout<<"Enter no of node"<<endl;
cin>>n;
cout<<"enter edges "<<endl;
int m;
cin>>m;
graph g;
for(int i=0;i<m;i++) {
int u, v;
cin>>u>>v;
g.insert(u,v,1);
}
g.print(n);
return 0;
}
But the problem with this code is that it will give correct answer only in the case when my node start from 0 in a continuous manner(0,1,2,3). But when I try to print adjacency list of this graph:
Then it is giving this output:
Can somebody tell me where am I wrong?
The edges you are adding aren't the same as the graph i picture, you are inputting edge 1, 3 instead of edge 1, 5.
It's printing the 0 because you started that for loop from i = 0 and it doesn't print node 5 for the same reason (the loop ends at 4 because you will have i < 4 + 1.
void print(int n) {
//↓↓↓ HERE
for(int i=0;i<n+1;i++) {
cout<<i<<"->";
for(auto j : adj[i]) {
cout<<j<<",";
}
cout<<endl;
}
}
Here is how I would change your code:
First, I changed the print() function a little (added the if() to see if the current row is empty and I changed the int n parameter to int maximum which will hold the highest value node so we know when to stop the for).
void print(int maximum)
{
for(int i=0; i<=maximum; i++)
{
if(!adj[i].empty())
{
cout<<i<<"->";
for(auto j : adj[i])
{
cout<<j<<",";
}
cout<<endl;
}
}
}
Then, in main() I added the maximum and aux variables in order to store the aforementioned highest value node. And I also changed the g.print(n) to g.print(maximum).
int main( )
{
int n, maximum = 0, aux;
cout<<"Enter no of node"<<endl;
cin>>n;
cout<<"enter edges "<<endl;
int m;
cin>>m;
graph g;
for(int i=0; i<m; i++)
{
int u, v;
cin>>u>>v;
g.insert(u,v,1);
aux = max(u, v);
maximum = max(maximum, aux);
}
g.print(maximum);
return 0;
}
However, I might not be Terry A. Davis, but I know that if you say you have 4 nodes, those 4 nodes will be 1 2 3 and 4. And I also know that any graph related problem will have nodes starting from 1, therefore every for loop would start from i = 1, or at least that's how I was taught. The way you did it might be correct too, but I am not sure.

How to compare the elements on two arrays on C++

A c ++ problem where I have to determine if the user hit the target. After entering the coordinates of where enemies coulb be, the user then enters more coordinates and I must compare them, print YES if the element[i] of the attacks matches any element of enemies [n]. I know that I'm comparing positions and not elements that's why it's not working but I'm lost.I also tried to solve it by making only one array but it felt better this way.
#include <iostream>
using namespace std;
int main()
{
int n, k, b;
int enemies[];
int attacks[];
cin>>n;
for (int i=0; i<n; i++) {
cin>>b;
enemies[i]=b;
}
cin>>k;
for (int i=0; i<k; i++) {
cin>>b;
atacks[i]=b;
}
for(int i=0; i<k; i++){
if(atacks[i]==enemies[i]){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
return 0;
}
Your code likely doesn't work because this line:
if(atacks[i]==enemies[i])
requires that matching attack and enemy should have the same index in their arrays.
As suggested in the comments, you need to iterate over ALL enemies for EACH attack, which is "O(n*k) solution"

In c++ code, set.erase(it) is halting execution, where it=set.begin() for a set of pairs, why is this happening?

Sorry for any inconvenience I am a beginner at C++ and was stuck with an empty set... Thank you for the helpful comments that helped me figure out what the problem was
I wrote a C++ code for a question in which I need to use Dijkstra's shortest path algorithm in n*log(n) time and so I am using set of pairs to obtain the vertex with shortest distance from source vertex. The code was not giving any errors at runtime but it wasn't giving the output either. So to see where it was getting stuck I used cout statements at certain points in the code and figured that the code is stopping execution right after the erase statement.
The statement is used in the code for erasing the first pair in the set and so the iterator pointing to set.begin() of the set is given as argument. It was earlier written in the format set.erase(iterator), but after searching for this problem on stack overflow I found someone saying iterator=set.erase(iterator) will solve the problem. I tried that and it still was getting stuck at that line, neither stopping execution and returning to the terminal nor giving a runtime error. I don't know what is wrong with this so I thought I would get some help here.
I am providing my code and a screenshot of the running too I would really appreciate your help.
#include<bits/stdc++.h>
using namespace std;
# define _z ios_base::sync_with_stdio(false); cin.tie(NULL);
# define ll long long int
#define mod 1000000007
int n;
set<pair<int, int>> dist;
void dij(vector<pair<int, int>> tree[], int decided[], int d[], vector<int>path[]) {
int mindist=INT_MAX, ind=0;
auto it=dist.begin();
ind=it->second;
cout<<"inbetween"<<endl;
dist.erase(it);
cout<<"inbetween"<<endl;
decided[ind]=1;
for(int i=0; i<tree[ind].size(); i++) {
int update=d[ind]+tree[ind][i].second;
int previous=d[tree[ind][i].first];
if(update<previous) {
pair<int, int>p=make_pair(previous, tree[ind][i].first);
dist.erase(dist.find(p));
p=make_pair(update, tree[ind][i].first);
dist.insert(p);
path[tree[ind][i].first]=path[ind];
cout<<*path[tree[ind][i].first].begin()<<endl;
path[tree[ind][i].first].push_back(tree[ind][i].first);
}
d[tree[ind][i].first]=min(update, previous);
}
}
int main()
{
int edges;
cin>>n>>edges;
vector<pair<int, int>> graph[n];
set<pair<int, int>> dist;
for(int i=0; i<edges; i++) {
int x, y, weight;
cin>>x>>y>>weight;
x--; y--;
graph[x].push_back({y, weight});
graph[y].push_back({x, weight});
}
int src=1;
//cin>>src;
cout<<"here"<<endl;
src--;
int d[n];
for(int i=0; i<n; i++) {
if(src==i) {
dist.insert({0, i});
d[i]=0;
}
else {
dist.insert({INT_MAX, i});
d[i]=INT_MAX;
}
}
int decided[n]={0};
vector<int> path[n];
path[src].push_back(src);
for(int i=0; i<n; i++) dij(graph, decided, d, path);
if(path[n-1].begin()==path[n-1].end()) cout<<-1<<endl;
for(auto it=path[n-1].begin(); it!=path[n-1].end(); it++) cout<<*it+1<<" ";
cout<<endl;
}
Image of the running code: Note that the highlighted lines are the problematic ones neither does iterator manipulation exist in the part of code that is getting stuck nor is the iterator accessed again after erasing.
It is only printing the line before the erase statement and not printing the one after...
The problem as told by user4581301 in the comments was that the iterator was pointing to the end() of the set, which means the set was empty as it was initialized to point to begin() of the set. Thus an undereferencable iterator was dereferenced resulting in undefined behavior, (this means it may not necessarily give a runtime error but rather provide an output when dereferenced). Although the program thus gets stuck at this line as a result of this invalid accessing.
The fault in the code was that set was defined globally but then was refined by the same name inside main, this meant when the values are filled in the set inside main, they are filled in the set that was defined within main not the one defined globally. But when accessing the set in the function dij, the global set is accessed which is actually empty!
Removing the redefinition in main would resolve the issue.
#include<bits/stdc++.h>
using namespace std;
# define _z ios_base::sync_with_stdio(false); cin.tie(NULL);
# define ll long long int
#define mod 1000000007
int n;
set<pair<int, int>> dist;
void dij(vector<pair<int, int>> tree[], int decided[], int d[], vector<int>path[]) {
int mindist=INT_MAX, ind=0;
auto it=dist.begin();
if(it==dist.end()) return;
ind=it->second;
dist.erase(it);
decided[ind]=1;
for(int i=0; i<tree[ind].size(); i++) {
int update=d[ind]+tree[ind][i].second;
int previous=d[tree[ind][i].first];
if(update<previous) {
pair<int, int>p=make_pair(previous, tree[ind][i].first);
dist.erase(dist.find(p));
p=make_pair(update, tree[ind][i].first);
dist.insert(p);
path[tree[ind][i].first]=path[ind];
path[tree[ind][i].first].push_back(tree[ind][i].first);
}
d[tree[ind][i].first]=min(update, previous);
}
}
int main()
{
int edges;
cin>>n>>edges;
vector<pair<int, int>> graph[n];
for(int i=0; i<edges; i++) {
int x, y, weight;
cin>>x>>y>>weight;
x--; y--;
graph[x].push_back({y, weight});
graph[y].push_back({x, weight});
}
int src=1;
src--;
int d[n];
for(int i=0; i<n; i++) {
if(src==i) {
dist.insert({0, i});
d[i]=0;
}
else {
dist.insert({INT_MAX, i});
d[i]=INT_MAX;
}
}
int decided[n]={0};
vector<int> path[n];
path[src].push_back(src);
for(int i=0; i<n; i++) dij(graph, decided, d, path);
if(path[n-1].begin()==path[n-1].end()) cout<<-1<<endl;
for(auto it=path[n-1].begin(); it!=path[n-1].end(); it++) cout<<*it+1<<" ";
cout<<endl;
}
The above code thus works perfectly fine. Below is the screenshot of the working code's output:
Here are some of the links provided in the comments that helped:
https://en.cppreference.com/w/cpp/language/ub (undefined behaviour)
https://ideone.com/5NY0q3 (code that proved begin is pointing to end)
https://en.cppreference.com/w/cpp/container/vector/erase (about erase)
https://codeforces.com/contest/20/problem/C (problem statement that the code pertains to)
P.S. The code finds the path through which the shortest distance between vertex 1 and vertex n of a graph with weighted edges can be obtained, in O(n*log(n)).
Thank you.

C++ Modify Djikstra's Algorithm To Give Second Shortest Path

How can you modify this Djikstra's algorithm to give the second shortest path? Another way I have done this function is using **G to pass a dynamically initialized 2D array.
I understand the shortest path here, however the second shortest path is confusing.
int main() {
int G[max][max]={{0,1,0,3,10},{1,0,5,0,0},{0,5,0,2,1},{3,0,2,0,6},{10,0,1,6,0}};
int n=5;
int u=0;
dijkstra(G,n,u);
return 0;
}
void dijkstra(int G[max][max],int n,int startnode) {
int cost[max][max],distance[max],pred[max];
int visited[max],count,mindistance,nextnode,i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(G[i][j]==0)
cost[i][j]=INFINITY;
else
cost[i][j]=G[i][j];
for(i=0;i<n;i++) {
distance[i]=cost[startnode][i];
pred[i]=startnode;
visited[i]=0;
}
distance[startnode]=0;
visited[startnode]=1;
count=1;
while(count<n-1) {
mindistance=INFINITY;
for(i=0;i<n;i++)
if(distance[i]<mindistance&&!visited[i]) {
mindistance=distance[i];
nextnode=i;
}
visited[nextnode]=1;
for(i=0;i<n;i++)
if(!visited[i])
if(mindistance+cost[nextnode][i]<distance[i]) {
distance[i]=mindistance+cost[nextnode][i];
pred[i]=nextnode;
}
count++;
}
for(i=0;i<n;i++)
if(i!=startnode) {
cout<<"\nDistance of node"<<i<<"="<<distance[i];
cout<<"\nPath="<<i;
j=i;
do {
j=pred[j];
cout<<"<-"<<j;
}while(j!=startnode);
}
}
This algorithm is from tutorials point.

Quick sort implementation in c++

I have pasted my implementation of the quicksort algorithm below. After some debugging I figured out that the recursion of the function quicksort() does not seem to terminate. But it seems to me that my algorithm is fine and I am not able to fix the bug.
/*
quicksort
*/
int a[20];
int partition(int left,int right, int*a)
{
//chose some pivot element- in this case i choose the middle one
int pivot=(left+right)/2;
int b[10],c[10],i=left,j=0;
int k=0;
int pivot_element=a[pivot];
//b is the left side ,c is the right side
while(i<=right)
{
if(a[i]!=pivot_element)
{
if(a[i]<a[pivot])
{
b[j++]=a[i];
}
else
{
c[k++]=a[i];
}
}
i++;
}
//combine
i=left;
for(int q=0;q<j;q++)
a[i++]=b[q];
a[i++]=pivot_element;
for(int p=0;p<k;p++)
a[i++]=c[p];
return j; //return the new position of the pivot
}
void quicksort(int left,int right,int *a)
{
int index=partition(left,right,a);
if(index-left>0)
quicksort(left,index,a);
if(right-index+1>0)
quicksort(index+1,right,a);
}
int main()
{
int size;
cin>>size;
for(int i=0;i<size;i++)
cin>>a[i];
quicksort(0,size-1,a);
for(int i=0;i<size;i++)
cout<<a[i]<<" ";
return 0;
}**
In your partition function, this:
return j;
should be this:
return left+j;
You could have detected this bug by testing the function, before writing other code that called it.
Your recursion lacks a stop criteria.