I am confused about topological sort - graph

I am new to graph theory and I am new to topological sort. All I know is that, to topologically sort some tasks, I have to run dfs on it and then sort the vertices according to their finishing time. Well, I have tried it. But somehow I am getting wrong answer.
Suppose for a graph with 5 vertices and 4 edges, and the edges being, 1->2, 2->3, 1->3, 1->5, my code gives the answer "4 1 5 2 3" when it should give "1 4 2 5 3". Is there anything wrong with my code or is there anything wrong with my idea of topological sort?
Here is my code.
#include<iostream>
#include<vector>
#include<cstdio>
#include<stack>
#define MAX 100000
using namespace std;
vector<int> adj_list[MAX];
int f[MAX], d[MAX];//discovery time and finishing time
int color[MAX];
int time;
stack<int> stk;
void dfs(int vertex);
void dfs_visit(int u);
int main(void)
{
freopen("input.txt", "r", stdin);
int vertex, edge;
//I am creating the adjacency list
cin >> vertex >> edge;
for(int i=1; i<=edge; i++)
{
int n1, n2;
cin >> n1 >> n2;
adj_list[n1].push_back(n2);
}
//I am starting the depth-first-search
dfs(vertex);
return 0;
}
void dfs(int vertex)
{
//If it's 0 then it means white
for(int i=1; i<=vertex; i++)
if(color[i]==0) dfs_visit(i);
//Here I am printing the vertices
while(stk.size())
{
cout << stk.top() << " ";
stk.pop();
}
cout << endl;
return;
}
void dfs_visit(int u)
{
//If it's 1 then it means grey
color[u]=1;
d[u]=++time;
for(int i=0; i<adj_list[u].size(); i++)
{
int v=adj_list[u][i];
if(color[v]==0) dfs_visit(v);
}
//If it's 2 then it means black
color[u]=2;
f[u]=++time;
//I am inserting the vertex in the stack when I am finished, searching it
stk.push(u);
}

Related

How can I reverse a series of numbers as quickly as possible?

I am trying to solve a question called 'smurf' on codebreaker.xyz, but my code is too slow. The task is to take in a series of numbers, one at a time, and reverse the array each time.
So for this input:
6
0 1 2 1 2 0
it should give the output 0 1 1 0 2 2.
The logic is correct and the code works, but how can I make it execute under 1 second for s <= 200,000...
This is the code in C++17:
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define int unsigned int
vector<int> S;
int s, t;
int32_t main(){
ios_base :: sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> s;
for(int i = 0; i < s; i++){
cin >> t;
S.push_back(t);
reverse(S.begin(), S.end());
}
for(int j = 0; j < s; j++){
cout << S[j] << " ";
}
}
As I understand your question, you need to reverse your container every time you add a new element. We can omit that by just adding the new number to the back or the front of the container, depending on if the container should be "reversed" or not at the moment. Since adding elements to the front of a vector is quite costly I would suggest using a list instead. An example would look like this
#include <iostream>
#include <list>
#include <ranges> //c++20
int main() {
std::list<int> numbers{};
bool reversed = false;
int N;
std::cin >> N;
while (N>0) {
int inputNumber;
std::cin >> inputNumber;
if(reversed){
numbers.push_front(inputNumber);
}
else{
numbers.push_back(inputNumber);
}
reversed = not reversed;
--N;
}
if(reversed){
for(const int i : numbers | std::views::reverse){
std::cout << i << ' ';
}
}
else{
for(const int i : numbers){
std::cout << i << ' ';
}
}
}

Finding the cycle in an undirected graph using BFS

I want to find first cycle in an undirected graph using BFS only(NOT DFS). All sources solved this problem with DFS but I have to find it using BFS. How can I find it? Thanks in advance!
Here below you will find the code to traverse a graph using BFS and find its cycles.
#include <stdio.h>
#include <queue>
using namespace std;
int nodes, edges, src;
int graph[100][100], color[100], prev[100];
const int WHITE = 0;
const int GRAY = 1;
const int BLACK = 2;
void print(int);
int main() {
printf("Nodes, edges, source? ");
scanf("%d %d %d ", &nodes, &edges, &src);
for(int i = 1; i <= edges; i++) {
printf("Edge %d: ", i);
int x, y;
scanf("%d %d", &x, &y);
graph[x][y] = 1;
}
//run BFS
queue<int> q; //create a queue
q.push(src); //1. put root node on the queue
do{
int u = q.front(); //2. pull a node from the beginning of the queue
q.pop();
printf("%d ", u); //print the node
for(int i = 1; i <= nodes; i++) { //4. get all the adjacent nodes
if((graph[u][i] == 1) //if an edge exists between these two nodes,
&& (color[i] == WHITE)) { //and this adjacent node is still WHITE,
q.push(i); //4. push this node into the queue
color[i] = GRAY; //color this adjacent node with GRAY
}
}
color[u] = BLACK; //color the current node black to mark it as dequeued
} while(!q.empty()); //5. if the queue is empty, then all the nodes havebeen visited
//find and print cycle from source
for(int i = 1; i <= nodes; i++) {
if(graph[i][src] == 1) {
print(i);
printf("%d\n\n", src);
}
}
return 0;
}
void print(int node) {
if(node == 0)
return;
print(prev[node]);
printf("%d -> ", node);
}
Also I recommend you to take a look at this brief and useful guide.

parallelize for loop using boost MPI

I am learning to use Boost.MPI to parallelize the large amount of computation, here below is just my simple test see if I can get MPI logic correctly. However, I did not get it to work. I used world.size()=10, there are total 50 elements in data array, each process will do 5 iteration. I would hope to update data array by having each process sending the updated data array to root process, and then the root process receives the updated data array then print out. But I only get a few elements updated.
Thanks for helping me.
#include <boost/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::mpi;
using namespace std;
#define max_rows 100
int data[max_rows];
int modifyArr(const int index, const int arr[]) {
return arr[index]*2+1;
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int num_rows = 50;
int my_number;
if (world.rank() == 0) {
for ( int i = 0; i < num_rows; i++)
data[i] = i + 1;
}
broadcast(world, data, 0);
for (int i = world.rank(); i < num_rows; i += world.size()) {
my_number = modifyArr(i, data);
data[i] = my_number;
world.send(0, 1, data);
//cout << "i=" << i << " my_number=" << my_number << endl;
if (world.rank() == 0)
for (int j = 1; j < world.size(); j++)
mpi::status s = world.recv(boost::mpi::any_source, 1, data);
}
if (world.rank() == 0) {
for ( int i = 0; i < num_rows; i++)
cout << "i=" << i << " results = " << data[i] << endl;
}
return 0;
}
Your problem is probably here:
mpi::status s = world.recv(boost::mpi::any_source, 1, data);
This is the only way data can get back to the master node.
However, you do not tell the master node where in data to store the answers it is getting. Since data is the address of the array, everything should get stored in the zeroth element.
Interleaving which elements of the array you are processing on each node is a pretty bad idea. You should assign blocks of the array to each node so that you can send entire chunks of the array at once. That will reduce communication overhead significantly.
Also, if your issue is simply speeding up for loops, you should consider OpenMP, which can do things like this:
#pragma omp parallel for
for(int i=0;i<100;i++)
data[i]*=4;
Bam! I just split that for loop up between all of my processes with no further work needed.

Base case condition in quick sort algorithm

For the quick sort algorithm(recursive), every time when it calls itself, it have the condition if(p < r). Please correct me if I am wrong: as far as I know, for every recursive algorithm, it has a condition as the time when it entered the routine, and this condition is used to get the base case. But I still cannot understand how to correctly set and test this condition ?
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
For my entire code, please refer to the following:
/*
filename : main.c
description: quickSort algorithm
*/
#include<iostream>
using namespace std;
void exchange(int* val1, int* val2)
{
int temp = *val1;
*val1 = *val2;
*val2 = temp;
}
int partition(int* arr, int p, int r)
{
int x = arr[r];
int j = p;
int i = j-1;
while(j<=r-1)
{
if(arr[j] <= x)
{
i++;
// exchange arr[r] with arr[j]
exchange(&arr[i],&arr[j]);
}
j++;
}
exchange(&arr[i+1],&arr[r]);
return i+1;
}
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
// driver program to test the quick sort algorithm
int main(int argc, const char* argv[])
{
int arr1[] = {13,19,9,5,12,8,7,4,21,2,6,11};
cout <<"The original array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
quickSort(arr1,0,11);
//print out the sorted array
cout <<"The sorted array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
cin.get();
return 0;
}
Your question is not quite clear, but I will try to answer.
Quicksort works by sorting smaller and smaller arrays. The base case is an array with less than 2 elements because no sorting would be required.
At each step it finds a partition value and makes it true that all the values to the left of the partition value are smaller and all values to the right of the partition value are larger. In other words, it puts the partition value in the correct place. Then it recursively sorts the array to the left of the partition and the array to right of the partition.
The base case of quicksort is an array with one element because a one element array requires no sorting. In your code, p is the index of the first element and r is the index of the last element. The predicate p < r is only true for an array of at least size 2. In other words, if p >= r then you have an array of size 1 (or zero, or nonsense) and there is no work to do.

Runtime allocation of multidimensional array

So far I thought that the following syntax was invalid,
int B[ydim][xdim];
But today I tried and it worked! I ran it many times to make sure it did not work by chance, even valgrind didn't report any segfault or memory leak!! I am very surprised. Is it a new feature introduced in g++? I always have used 1D arrays to store matrices by indexing them with correct strides as done with A in the program below. But this new method, as with B, is so simple and elegant that I have always wanted. Is it really safe to use? See the sample program.
PS. I am compiling it with g++-4.4.3, if that matters.
#include <cstdlib>
#include <iostream>
int test(int ydim, int xdim) {
// Allocate 1D array
int *A = new int[xdim*ydim](); // with C++ new operator
// int *A = (int *) malloc(xdim*ydim * sizeof(int)); // or with C style malloc
if (A == NULL)
return EXIT_FAILURE;
// Declare a 2D array of variable size
int B[ydim][xdim];
// populate matrices A and B
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++) {
A[y*xdim + x] = y*xdim + x;
B[y][x] = y*xdim + x;
}
}
// read out matrix A
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++)
std::cout << A[y*xdim + x] << " ";
std::cout << std::endl;
}
std::cout << std::endl;
// read out matrix B
for(int y = 0; y < ydim; y++) {
for(int x = 0; x < xdim; x++)
std::cout << B[y][x] << " ";
std::cout << std::endl;
}
delete []A;
// free(A); // or in C style
return EXIT_SUCCESS;
}
int main() {
return test(5, 8);
}
int b[ydim][xdim] is declaring a 2-d array on the stack. new, on the other hand, allocates the array on the heap.
For any non-trivial array size, it's almost certainly better to have it on the heap, lest you run yourself out of stack space, or if you want to pass the array back to something outside the current scope.
This is a C99 'variable length array' or VLA. If they are supported by g++ too, then I believe it is an extension of the C++ standard.
Nice, aren't they?

Resources