std::bad_alloc during dijkstra calculation for big dataset - c++

I am trying to solve shortest path for big graph using dijkstra algorithm.
Problem is when I am executing program in CLion I am getting std::bad alloc, always at node 491, however when I tried do the same on my Ubuntu VM, I am getting core dumped on the beggining.
I am new to c++ so it is hard for me to understand why does it happen.
Here is my code:
Utils:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <ctime>
#define INFINITY 9999999
int maxNode = 0;
using namespace std;
vector<int> loadFile(const string &path) {
vector<int> graph;
ifstream file;
file.open(path);
if (!file.fail()) {
string line;
while (getline(file, line)) {
stringstream ss(line);
for (int i; ss >> i;) {
if (i + 1 > maxNode)
maxNode = i + 1;
graph.push_back(i);
if (ss.peek() == ';')
ss.ignore();
}
}
file.close();
}
return graph;
}
int **formatGraph(vector<int> inData) {
int **graph = 0;
int currentIndex = 0;
int srcNode = inData[0];
int dstNode = inData[1];
int cost = inData[2];
graph = new int *[maxNode];
for (int i = 0; i < maxNode; i++) {
graph[i] = new int[maxNode];
for (int j = 0; j < maxNode; j++) {
if (srcNode == i && dstNode == j) {
graph[i][j] = cost;
currentIndex++;
srcNode = inData[currentIndex * 3];
dstNode = inData[currentIndex * 3 + 1];
cost = inData[currentIndex * 3 + 2];
//printf("%d %d\n", i, j);
} else
graph[i][j] = 0;
}
}
for (int i = 0; i < maxNode; i++) {
for (int j = 0; j < maxNode; j++) {
graph[j][i] = graph[i][j];
}
}
return graph;
}
Algorithm:
void dijkstra(int **G, int n, int startnode) {
printf("%d\n", startnode);
int **cost = new int *[maxNode];
int distance[maxNode], pred[maxNode];
int visited[maxNode], count, mindistance, nextnode, i, j;
for (i = 0; i < n; i++) {
cost[i] = new int[maxNode];
for (j = 0; j < n; j++)
cost[i][j] = 0;
}
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++;
}
delete[] cost;
for (i = 0; i < n; i++)
if (i != startnode) {
j = i;
do {
j = pred[j];
} while (j != startnode);
}
}
And here is my main function:
int main() {
vector<int> graph = loadFile("..\\data\\newFile2.csv");
int **graphConverted = formatGraph(graph);
//printMatrix(graphConverted);
clock_t begin = clock();
for (int i = 0; i < maxNode; i++)
dijkstra(graphConverted, maxNode, i);
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
printf("\nTime: %f", elapsed_secs);
return 0;
}
First the data is loaded into vector, and then it is converted to adjacency matrix.
Data is stored in form:
src_node;dst_node;cost
1;2;3
1;3;30
1;66;20
etc.
Dataset consinsts of 1004 nodes and 25571 edges.
Could you please suggest me any solution how to fix this?

In dijkstra you have dynamic memory allocations here:
int **cost = new int *[maxNode];
and here in a loop over i:
cost[i] = new int[maxNode];
You have only one call to delete[] in this function:
delete[] cost;
So all the allocations from the second new line are guaranteed to be leaked. After a while you will be out-of-memory, resulting in the std::bad_alloc.
You need to match each new[] call with exactly one delete[] call.
Don't use new/delete at all. Instead declare all your arrays as std::vector, which will take care of this automatically.
Also don't use variable-length arrays such as
int distance[maxNode], pred[maxNode];
They are a non-standard compiler extension. Make these std::vector as well.

Related

Code runs fine through a debugger but crashes on execution

Can someone point out or give a hint on what's going on? Why is it when I run the code line-by-line using the built-in debugger, it gives the correct returnAry, but crashes when I try to execute the program?
No debugger:
With debugger:
Here is my code:
#include <iostream>
#include "fraction.h"
#include "fractionUtilities.h"
using namespace std;
int* getUncommon(Fraction*, int);
int main() {
Fraction testAry[] = { 1201, 6266, 35, 77 };
int size = 4;
int* result;
result = getUncommon(testAry, size);
for (int i = 0; i < result[0] + 1; i++) {
cout << result[i] << endl;
}
return 0;
}
int* getUncommon(Fraction* ary, int size) {
int* returnAry = 0;
int tmp;
int** digitInfoAry = new int*[size];
int i, j;
int sizeAry = 10;
int digitAry[10]{ 0 };
int uncommonDigitCount = 0;
for (i = 0; i < sizeAry; i++) {
*(digitInfoAry + i) = new int[sizeAry] {0};
}
for (i = 0; i < size; i++) {
tmp = (ary + i)->getNum() < 0 ? -(ary + i)->getNum() : (ary + i)->getNum();
do {
*(*(digitInfoAry + i) + tmp % 10) = 1;
tmp /= 10;
} while (tmp != 0);
}
for (i = 0; i < sizeAry; i++) {
for (j = 0; j < size; j++) {
digitAry[i] += *(*(digitInfoAry + j) + i);
}
}
for (i = 0; i < sizeAry; i++) {
if (digitAry[i] == 1) {
uncommonDigitCount++;
}
}
returnAry = new int[uncommonDigitCount + 1];
*returnAry = uncommonDigitCount;
if (uncommonDigitCount != 0) {
for (i = 0, j = 1; i < sizeAry; i += 2) {
if (digitAry[i] % 2 == 1) {
returnAry[j] = i;
j++;
}
}
for (i = 1; i < sizeAry; i += 2) {
if (digitAry[i] % 2 == 1) {
returnAry[j] = i;
j++;
}
}
}
return returnAry;
}
Thank you ahead of time for your help, I really cannot figure out what is going on, it's driving me insane!
Try to fix this:
int** digitInfoAry = new int*[size];
...
for (i = 0; i < sizeAry; i++) {
*(digitInfoAry + i) = new int[sizeAry] {0};
}
Then loop runs from 0 to sizeAry indices goes beyond allocated memory.

c++ error: vector subscript out of range, line 1201

New to c++. I'm getting the "out of range" error message when try to debug the code. I tried to used resize(), but it is still not fixed. The code is to read instructions into a 2d vector and print out the graph.
What am I doing wrong?
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<sstream>
using namespace std;
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>&, Pattern&);
void Builder(Pattern&, vector<vector<char>>&);
void Printer(vector<vector<char>>&);
int main()
{
Pattern characters;
vector<vector<char>> key;
characters.colNum = 3;
characters.rowNum = 3;
characters.token = '#';
characters.isOuter = false;
characters.isTriangular = false;
Builder(characters, key);
Printer(key);
}
void Builder(Pattern& character, vector<vector<char>>& matrix)
{
int i = 0, j = 0;
char c;
if (character.token == 0)
c = 'a';
else
c = character.token;
matrix.resize(character.rowNum);
for (int i = 0; i < character.rowNum; i++){
if (character.isTriangular)
matrix[i].resize(i + 1);
else
matrix[i].resize(character.colNum);
if (character.isOuter)
{
if (character.isTriangular)
{
if (i = j)
matrix[i][j] = c;
else
matrix[character.rowNum - 1][i] = matrix[i][0] = c;
}
else
matrix[0][j] = matrix[i][0] = matrix[character.rowNum - 1][j] = matrix[i][character.colNum - 1] = c;
i++;
j++;
}
else
{
if (character.isOuter)
{
while (i <= j){
for (i = 0; i < character.rowNum; i++)
for (j = 0; i < character.colNum; j++)
matrix[i][j] = c;
}
}
else
for (i = 0; i < character.rowNum; i++)
for (j = 0; i < character.colNum; j++)
matrix[i][j] = c;
}
c++;
}
}
void Printer(vector<vector<char>>& print)
{
for (int i = 0; i < print.size(); i++){
for (int j = 0; j < print[i].size(); j++)
{
cout << print[i][j] << endl;
}
}
}
if (i = j) should be if (i == j).
if (i = j) do a assignment and test if i != 0.
Other problems:
while (i <= j){
for (i = 0; i < character.rowNum; i++)
for (j = 0; i < character.colNum; j++) // You test `i` instead of j
matrix[i][j] = c;
// Once test fixed
// Here `i == character.rowNum` and `j == character.colNum` (if `character.rowNum != 0`)
// So the while loop condition doesn't change and may so do infinite loop
}

Parent array is always zero in prims algorithm

I have the following function to find the parent array in order to obtain a minimum spanning tree of a graph using Prim's algorithm.
#include<stdlib.h>
#include <limits.h>
#include <iostream>
int printMST(int parent[], int n, int** graph)
{
for (int i = 1; i < n; i++)
std::cout<<parent[i]<<" - "<<i<<" "<<graph[i][parent[i]]<<"\n";
}
int* prim(int** graph,int no_of_vertices);
int main(){
int no_of_vertices;
std::cin>>no_of_vertices;
int** graph = new int*[no_of_vertices];
for(int i = 0; i < no_of_vertices; ++i)
graph[i] = new int[no_of_vertices];
for(int i = 0; i <no_of_vertices; ++i)
for(int j = 0; j < no_of_vertices; ++j)
std::cin>>graph[i][j];
int* parent;
parent= prim(graph,no_of_vertices);
// Print the solution
printMST(parent, no_of_vertices, graph);
return 0;
}
int nodeWithMinKey(int key[],bool mst[], int no_of_vertices)
{
int min=1000,min_index;
for(int i=0;i<no_of_vertices;i++)
{
if(mst[i]=false && key[i]<min)
{
min=key[i];
min_index=i;
}
}
return min_index;
}
int* prim(int** graph, int no_of_vertices){
int* parent = (int*)malloc(sizeof(int)*no_of_vertices);
int key[100];
bool mst[100];
int i;
for(i = 0; i<no_of_vertices; i++)
{
key[i] = 1000;
mst[i] = false;
}
key[0] = 0;
parent[0] = -1;
for(i = 0; i<no_of_vertices-1; i++)
{
int u = nodeWithMinKey(key, mst, no_of_vertices);
mst[u] = true;
for(int v = 0; v<no_of_vertices; v++)
{
if(graph[u][v] && mst[v] == false && graph[u][v] < key[v])
{
parent[v] = u;
key[v] = graph[u][v];
}
}
}
return parent;
}
But the parent array is having all the values as '0'(zero), don't know where the condition has gone wrong.
This line
if(mst[i]=false && key[i]<min)
has an assignment = instead of a comparison ==. This will always cause the if test to always fail, so your min_index will never be set.

Kosaraju's Algorithm for spoj's BOTTOM

I am trying to solve http://www.spoj.com/problems/BOTTOM/
Here are the steps I am following:
1) Find the strongly connected components using Kosaraju's algorithm. 2) Consider a strongly connected component. Consider an edge u. Now consider all edges from u to some vertice v. If v lies in some other SCC, eliminate the whole strongly conected component. Else include all the elements in the solution.
However, I am constantly getting WA. Please help.
Here is my code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <fstream>
#include <iterator>
#include <queue>
using namespace std;
int k = 0;
int V, E;
bool fix[5001];
bool fix2[5001];
int compNum[5001];
void dfs(int v, vector< vector<int> >&G, bool *fix, vector <int> &out) {
fix[v] = true;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
if (!fix[u]) {
fix[u] = true;
dfs(u, G, fix, out);
}
}
out.push_back(v);
}
void dfs2(int v, vector< vector<int> >&G, bool *fix2, vector < vector<int> > &components) {
fix2[v] = true;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
if (!fix2[u]) {
fix2[u] = true;
dfs2(u, G, fix2, components);
}
}
components[k].push_back(v);
compNum[v] = k;
}
int main() {
int a, b;
while (true) {
cin >> V; if (V == 0) break; cin >> E;
vector< vector<int> >G(V + 1);
vector< vector<int> >G2(V + 1);
vector<int>out;
vector < vector<int> >components(V + 1);
for (int i = 0; i < E; i++) {
cin >> a >> b;
G[a].push_back(b);
G2[b].push_back(a);
}
for (int i = 1; i <= V; i++) {
if (!fix[i])
dfs(i, G, fix, out);
}
reverse(out.begin(), out.end());
for (int i = 0; i < out.size(); i++){
if (!fix2[out[i]]) {
dfs2(out[i], G2, fix2, components);
k++;
}
}
vector<int>gamotana;
for (int i = 0; i < components.size(); i++) {
for (int j = 0; j < components[i].size(); j++) {
bool check = true;
for (int z = 0; z < G[components[i][j]].size(); z++)
{
if (compNum[G[components[i][j]][z]] != i)
{
check = false; goto next123;
}
}
if (check)
gamotana.push_back(components[i][j]);
}
next123:;
}
sort(gamotana.begin(), gamotana.end());
for (int i = 0; i < gamotana.size(); i++)
cout << gamotana[i] << " ";
for (int i = 0; i < 5001; i++) {
fix[i] = false;
fix2[i] = false;
compNum[i] = -1;
}
k = 0;
cout << endl;
}
return 0;
}
In your algorithm description you say you eliminate the entire connected component if some edge leads to a different component.
However, in your code you appear to add all vertices j in component i to your solution until you find an edge leading out. In other words, even if a component is not a sink you may still incorrectly report some of the vertices as being sinks.
I imagine you should do something more like this:
for (int i = 0; i < components.size(); i++) {
for (int j = 0; j < components[i].size(); j++) {
for (int z = 0; z < G[components[i][j]].size(); z++)
{
if (compNum[G[components[i][j]][z]] != i)
{
goto next123;
}
}
}
for (int j = 0; j < components[i].size(); j++)
gamotana.push_back(components[i][j]);
next123:;
}
Of course, there may be more issues. I would recommend you try constructing and testing some small examples first, and perhaps testing against a brute force solver to identify failing cases.
#include<bits/stdc++.h>
using namespace std;
void dfs(vector<int>* edges, stack<int>& finishedVertices, bool* visited, int n, int start){
visited[start] = true;
for(int i = 0 ; i < edges[start].size() ; i++){
int node = edges[start][i];
if(!visited[node]){
dfs(edges, finishedVertices, visited, n, node);
}
}
finishedVertices.push(start);
}
void dfs_reverse(vector<int>* edgesT, bool* visited, unordered_map<int,vector<int>>& SCC, int node, int k){
SCC[k].push_back(node);
visited[node] = true;
for(int i = 0 ; i < edgesT[node].size() ; i++){
int new_node = edgesT[node][i];
if(!visited[new_node]){
dfs_reverse(edgesT, visited, SCC, new_node, k);
}
}
}
void getSCC(vector<int>* edges, vector<int>* edgesT, int n){
bool* visited = new bool[n];
for(int i = 0 ; i < n ; i++){
visited[i] = false;
}
stack<int> finishedVertices;
for(int i = 0 ; i < n ; i++){
if(!visited[i]){
dfs(edges, finishedVertices, visited, n, i);
}
}
unordered_map<int,vector<int>> SCC;
int k = 0;
for(int i = 0 ; i < n ; i++){
visited[i] = false;
}
while(!finishedVertices.empty()){
int node = finishedVertices.top();
finishedVertices.pop();
if(!visited[node]){
dfs_reverse(edgesT, visited, SCC, node, k);
k++;
}
}
int flag = 1;
vector<int> ans;
vector<int> bottom;
for(int i = 0 ; i < k ; i++){
for(int j = 0 ; j < SCC[i].size(); j++){
ans.push_back(SCC[i][j]);
}
for(int m = 0 ; m < ans.size() ; m++){
int node = ans[m];
for(int j = 0 ; j < edges[node].size() ; j++){
int new_node = edges[node][j];
vector<int> :: iterator it;
it = find(ans.begin(), ans.end(), new_node);
if(it == ans.end()){
flag = 0;
break;
}
}
if(flag == 0)
break;
}
if(flag == 1){
for(int j = 0 ; j < ans.size() ; j++)
bottom.push_back(ans[j]);
}
flag = 1;
ans.clear();
}
sort(bottom.begin(), bottom.end());
for(int i = 0 ; i < bottom.size() ; i++)
cout << bottom[i] + 1 << " ";
cout << endl;
}
int main(){
while(true){
int n;
cin >> n;
if(n == 0)
break;
vector<int>* edges = new vector<int>[n];
vector<int>* edgesT = new vector<int>[n];
int e;
cin >> e;
for(int i = 0 ; i < e ; i++){
int x, y;
cin >> x >> y;
edges[x-1].push_back(y-1);
edgesT[y-1].push_back(x-1);
}
getSCC(edges, edgesT, n);
delete [] edges;
delete [] edgesT;
}
return 0;
}

TLE on BFS from several sources

I'm trying to solve this problem: http://olimpiada-informatica.org/?cmd=downloadE&pbm=velo101&ext=pdf It is in spanish but I will try to translate it here:
You are about to land on earth when you find out that someone has released some Velociraptors in the landing strip.
The landing trip has a rectangular shape. We mark with a dot (.)an empty spot, with a V the velociraptors and with a # the spots with obstacles on them (you cannot land on them).
It takes a second to the velociraptors to go to another spot, but they can only move horizontally and vertically.
You are asked to mark with an X those spots in which, landing on them, you would maximize your remaining lifetime.
I have done an algorithm in which I take every position of the velociraptors and make a BFS on every position, but I'm getting TLE, here is my code:
http://ideone.com/a6BVv3
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
using namespace std;
int cost[501][501],xx,yy,n,m;
char mat[501][501];
bool visit[501][501],first = true;
int a[] = {-1,0,0,1}, b[] = {0,-1,1,0};
void check(int x,int y,int level) {
cost[x][y] = level;
for(int i = 0; i < 4; ++i) {
xx = x + a[i];
yy = y + b[i];
if(0 <= xx and xx < n and 0 <= yy and yy < m and mat[xx][yy] == '.') {
if(!visit[xx][yy] or level + 1 < cost[xx][yy]) {
visit[xx][yy] = true;
check(xx,yy,level + 1);
}
}
}
}
int max() {
int r = -1;
for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) if(mat[i][j] == '.') r = max(r,cost[i][j]);
return r;
}
void show() {
if(!first) puts("---");
int r = max();
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(cost[i][j] == r) printf("X");
else printf("%c",mat[i][j]);
}
puts("");
}
}
int main() {
while(scanf("%d %d",&n,&m) == 2) {
queue<pair<int,int> > cola;
for(int i = 0; i < n; ++i) {
scanf("\n");
for(int j = 0; j < m; ++j) {
scanf("%c",&mat[i][j]);
if(mat[i][j] == 'V') cola.push(make_pair(i,j));
}
}
memset(cost,-1,sizeof cost);
memset(visit,0,sizeof visit);
while(!cola.empty()) {
pair<int,int> aux = cola.front();
visit[aux.first][aux.second] = true;
check(aux.first, aux.second,0);
cola.pop();
}
show();
first = false;
}
return 0;
}
Does anyone know how could I improve my algorithm?
EDIT
Ok, I was able to solve the problem, here is the code if anyone is interested:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
using namespace std;
int cost[501][501],n,m;
char mat[501][501];
bool visit[501][501],first = true;
queue<pair<int,int> > cola;
int a[] = {-1,0,0,1}, b[] = {0,-1,1,0};
int max() {
int r = -1;
for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j) if(mat[i][j] == '.') r = max(r,cost[i][j]);
return r;
}
void show() {
if(!first) puts("---");
int r = max();
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(cost[i][j] == r) printf("X");
else printf("%c",mat[i][j]);
}
puts("");
}
}
int main() {
int cont = 0,x,y,xx,yy,level;
while(scanf("%d %d",&n,&m) == 2) {
for(int i = 0; i < n; ++i) {
scanf("\n");
for(int j = 0; j < m; ++j) {
scanf("%c",&mat[i][j]);
if(mat[i][j] == 'V') cola.push(make_pair(i,j));
}
}
memset(cost,-1,sizeof cost);
memset(visit,0,sizeof visit);
while(!cola.empty()) {
int s_cola = cola.size();
for(int i = 0; i < s_cola; ++i) {
x = cola.front().first, y = cola.front().second;
cola.pop();
level = cost[x][y];
for(int i = 0; i < 4; ++i) {
xx = x + a[i], yy = y + b[i];
if(0 <= xx and xx < n and 0 <= yy and yy < m and mat[xx][yy] == '.') {
if(!visit[xx][yy] or level + 1 < cost[xx][yy]) {
visit[xx][yy] = true;
cost[xx][yy] = level + 1;
cola.push(make_pair(xx,yy));
}
}
}
}
}
show();
first = false;
}
return 0;
}
You're doing a depth-first search of the whole graph in check(). Integrate that with the loop in main() instead of trying to find shortest paths depth-first.