Isomorphic graph parallel code implementation using openmp - c++

I am trying to implement a parallel code for graph isomorphism(checking if 2 graphs are isomorphic or not) using openmp. I have the sequential code below, written in C++ which works only for regular graphs.
I have taken the input from a text file (input.txt) which contains number of nodes and 2 adjacency matrices representing 2 graphs. The output.txt file indicates whether the graphs are isomorphic or NON isomorphic along with the execution time.
I have used is_regular() function to check if a graph is regular graph or not.
Can someone please help me parallelize this code using openmp.
#include <time.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
using namespace std;
bool is_regular(vector<string> &adj) {
int nv = adj.size();
int cnt = 0;
for (int j = 0; j < nv; ++j)
if (adj[0][j] == '1') ++cnt;
for (int i = 1; i < nv; ++i) {
int sch = 0;
for (int j = 0; j < nv; ++j)
if (adj[i][j] == '1') ++sch;
if (sch != cnt) return false;
}
return true;
}
vector<vector<int> > foo1(vector<string> &adj, char R) {
int nv = adj.size();
vector<vector<int> > res;
for (int v1 = 0; v1 < nv; ++v1) {
vector<int> tmp;
vector<bool> b(nv);
vector<int> p, q;
p.push_back(v1);
b[v1] = true;
while (!p.empty()) {
q.clear();
for (size_t i = 0; i < p.size(); ++i) {
for (int j = 0; j < nv; ++j)
{
if (!b[j] && adj[p[i]][j] == R) {
b[j] = true;
q.push_back(j);
}
}
}
if (q.empty()) break;
vector<int> d(p.size());
vector<int> e(q.size());
for (size_t i = 0; i < p.size(); ++i) {
for (size_t j = 0; j < q.size(); ++j) {
if (adj[p[i]][q[j]] == R) {++d[i]; --e[j];}
}
}
sort(d.begin(), d.end());
sort(e.begin(), e.end());
copy(d.begin(), d.end(), back_inserter(tmp));
copy(e.begin(), e.end(), back_inserter(tmp));
p.swap(q);
}
res.push_back(tmp);
}
sort(res.begin(), res.end());
return res;
}
vector<vector<int> > foo2(vector<string> &adj, char R) {
int nv = adj.size();
vector<vector<int> > res;
for (int v1 = 0; v1 < nv; ++v1) {
for (int v2 = v1 + 1; v2 < nv; ++v2) {
vector<int> tmp;
vector<bool> b(nv);
vector<int> p, q;
p.push_back(v1);
p.push_back(v2);
b[v1] = true;
b[v2] = true;
while (!p.empty()) {
q.clear();
for (size_t i = 0; i < p.size(); ++i) {
for (int j = 0; j < nv; ++j) {
if (!b[j] && adj[p[i]][j] == R) {
b[j] = true;
q.push_back(j);
}
}
}
if (q.empty()) break;
vector<int> d(p.size());
vector<int> e(q.size());
for (size_t i = 0; i < p.size(); ++i) {
for (size_t j = 0; j < q.size(); ++j) {
if (adj[p[i]][q[j]] == R) {++d[i]; --e[j];}
}
}
sort(d.begin(), d.end());
sort(e.begin(), e.end());
copy(d.begin(), d.end(), back_inserter(tmp));
copy(e.begin(), e.end(), back_inserter(tmp));
p.swap(q);
}
res.push_back(tmp);
}
}
sort(res.begin(), res.end());
return res;
}
vector<vector<int> > foo3(vector<string> &adj, char R) {
int nv = adj.size();
vector<vector<int> > res;
for (int v1 = 0; v1 < nv; ++v1) {
for (int v2 = v1 + 1; v2 < nv; ++v2) {
for (int v3 = v2 + 1; v3 < nv; ++v3) {
vector<int> tmp;
vector<bool> b(nv);
vector<int> p, q;
p.push_back(v1);
p.push_back(v2);
p.push_back(v3);
b[v1] = true;
b[v2] = true;
b[v3] = true;
while (!p.empty()) {
q.clear();
for (size_t i = 0; i < p.size(); ++i) {
for (int j = 0; j < nv; ++j) {
if (!b[j] && adj[p[i]][j] == R) {
b[j] = true;
q.push_back(j);
}
}
}
if (q.empty()) break;
vector<int> d(p.size());
vector<int> e(q.size());
for (size_t i = 0; i < p.size(); ++i) {
for (size_t j = 0; j < q.size(); ++j) {
if (adj[p[i]][q[j]] == R) {++d[i]; --e[j];}
}
}
sort(d.begin(), d.end());
sort(e.begin(), e.end());
copy(d.begin(), d.end(), back_inserter(tmp));
copy(e.begin(), e.end(), back_inserter(tmp));
p.swap(q);
}
res.push_back(tmp);
}
}
}
sort(res.begin(), res.end());
return res;
}
int main() {
int nt = 1;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
int tc = 0;
while (cin >> n) {
vector<string> adj1(n);
vector<string> adj2(n);
for (int i = 0; i < n; ++i) cin >> adj1[i];
for (int i = 0; i < n; ++i) cin >> adj2[i];
clock_t start = clock();
string answer = "NON-isomorphic";
if (!is_regular(adj1) || !is_regular(adj2)) {
answer = "Non regular graph";
goto mmm;
}
if (foo1(adj1,'1') != foo1(adj2,'1') || foo1(adj1,'0') != foo1(adj2,'0')) {
answer += " * ";
goto mmm;
}
if (foo2(adj1,'1') != foo2(adj2,'1') || foo2(adj1,'0') != foo2(adj2,'0')) {
answer += " ** ";
goto mmm;
}
if (foo3(adj1,'1') != foo3(adj2,'1') || foo3(adj1,'0') != foo3(adj2,'0')) {
answer += " ***";
goto mmm;
}
answer = "isomorphic";
mmm:
++tc;
printf("%d) n = %d %s", tc, n, answer.c_str());
printf(" %f\n", (double)(clock() - start) / CLOCKS_PER_SEC);
}
return 0;
}

Related

C++ - Calculating the inverse of a matrix

I've tried to write a program that should be able to calculate the inverse of a matrix:
Here's what I have so far:
#include <iostream>
#include <vector>
#include <math.h>
#include <iomanip>
#include <stdexcept>
double getDeterminant(const std::vector<std::vector<double>> vect) {
if(vect.size() != vect[0].size()) {
throw std::runtime_error("Matrix is not quadratic");
}
int dimension = vect.size();
if(dimension == 0) {
return 1;
}
if(dimension == 1) {
return vect[0][0];
}
//Formula for 2x2-matrix
if(dimension == 2) {
return vect[0][0] * vect[1][1] - vect[0][1] * vect[1][0];
}
double result = 0;
int sign = 1;
for(int i = 0; i < dimension; i++) {
//Submatrix
std::vector<std::vector<double>> subVect(dimension - 1, std::vector<double> (dimension - 1));
for(int m = 1; m < dimension; m++) {
int z = 0;
for(int n = 0; n < dimension; n++) {
if(n != i) {
subVect[m-1][z] = vect[m][n];
z++;
}
}
}
//recursive call
result = result + sign * vect[0][i] * getDeterminant(subVect);
sign = -sign;
}
return result;
}
std::vector<std::vector<double>> getTranspose(const std::vector<std::vector<double>> matrix1) {
//Transpose-matrix: height = width(matrix), width = height(matrix)
std::vector<std::vector<double>> solution(matrix1[0].size(), std::vector<double> (matrix1.size()));
//Filling solution-matrix
for(size_t i = 0; i < matrix1.size(); i++) {
for(size_t j = 0; j < matrix1[0].size(); j++) {
solution[j][i] = matrix1[i][j];
}
}
return solution;
}
std::vector<std::vector<double>> getCofactor(const std::vector<std::vector<double>> vect) {
if(vect.size() != vect[0].size()) {
throw std::runtime_error("Matrix is not quadratic");
}
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
std::vector<std::vector<double>> subVect(vect.size() - 1, std::vector<double> (vect.size() - 1));
for(std::size_t i = 0; i < vect.size(); i++) {
for(std::size_t j = 0; j < vect[0].size(); j++) {
int p = 0;
for(size_t x = 0; x < vect.size(); x++) {
if(x == i) {
continue;
}
int q = 0;
for(size_t y = 0; y < vect.size(); y++) {
if(y == j) {
continue;
}
subVect[p][q] = vect[x][y];
q++;
}
p++;
}
solution[i][j] = pow(-1, i + j) * getDeterminant(subVect);
}
}
return solution;
}
std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
if(getDeterminant(vect) == 0) {
throw std::runtime_error("Determinant is 0");
}
double d = 1.0/getDeterminant(vect);
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] = vect[i][j] * d;
}
}
return getTranspose(getCofactor(solution));
}
void printMatrix(const std::vector<std::vector<double>> vect) {
for(std::size_t i = 0; i < vect.size(); i++) {
for(std::size_t j = 0; j < vect[0].size(); j++) {
std::cout << std::setw(8) << vect[i][j] << " ";
}
std::cout << "\n";
}
}
int main() {
std::vector<std::vector<double>> matrix(3, std::vector<double> (3));
matrix = {
{1,2,3},
{4,5,6},
{7,8,8}
};
printMatrix(getInverse(matrix));
return 0;
}
The functions for calculating the determinant, the transpose- and the cofactor-matrix work correctly (as far as I can see), but the function for calculating the inverse-matrix doesn't.
I searched the internet and found this, which uses the same function for calculating the inverse.
Is this formula incorrect, or do you have any other idea, why it doesnt work?
The matrix I am using is
and the inverse of it should be
First of all, thanks for your comments.
The problem was the order of execution.
The correct solution is:
std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
if(getDeterminant(vect) == 0) {
throw std::runtime_error("Determinant is 0");
}
double d = 1.0/getDeterminant(vect);
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] = vect[i][j];
}
}
solution = getTranspose(getCofactor(solution));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] *= d;
}
}
return solution;
}
I know this is an old question but your code does not work when the input matrix's dimension is 1. Here is a workaround that I used:
vector<vector<double>> inverse(const vector<vector<double>> A) {
double d = 1.0/det(A);
vector<vector<double>> solution(A.size(), vector<double> (A.size()));
if(A.size() == 1){
vector<double> ans = {0};
ans[0] = 1.0/det(A);
solution[0] = ans;
return solution;
}
for(size_t i = 0; i < A.size(); i++) {
for(size_t j = 0; j < A.size(); j++) {
solution[i][j] = A[i][j] * d;
}
}
return transpose(cofactor(solution));
}

std::bad_alloc during dijkstra calculation for big dataset

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.

BFS replace an array with a map C++

How to replace a common array int playersStartPos[100] with a std::map in BFS algorithm? This algorithm finds the shortest path between all two vertices. It works, but in some cases it takes more than 1 second to proceed all vertices. So I have to replace this loop for (int j = 0; j < K; j++) { //BAAAADDDDDDwith a std::map and do the search by key. But it appears it works even worse (should be better I know it 100%). How to modify an algorithm to use std::map?.
Thank you.
**INPUT**
7 3
1 1
2 0 2
2 1 4
1 4
3 2 3 5
2 4 6
1 5
0 3 6
**OUTPUT**
0 4 5
4 0 3
5 3 0
1 2
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <map>
using namespace std;
vector<vector<int>> adjList;
int N = 0; //vertices quantity
int K = 0; //players quantity
int playersStartPos[100];
int res[100][100];
void read()
{
FILE* fp = fopen("input2.txt", "r");
fscanf(fp, "%d", &N);
fscanf(fp, "%d", &K);
for (int i = 0; i < N; i++) {
int size = 0;
fscanf(fp, "%d", &size);
vector<int> adjacency(size);
for (int j = 0; j < size; j++) {
int to = 0;
fscanf(fp, "%d", &to);
adjacency[j] = to;
}
adjList.push_back(adjacency);
}
for (int player = 0; player < K; player++) {
int pos = 0;
fscanf(fp, "%d", &pos);
//cout << pos << " ";
playersStartPos[player] = pos;
}
//fclose(fp);
}
int bfs(int start, int ind)
{
queue<int> q;
vector<bool> used(N, 0);
vector<int> path(N);
q.push(start);
used[start] = true;
path[start] = -1;
while (!q.empty()) {
int currentVertex = q.front();
q.pop();
for (size_t i = 0; i < adjList[currentVertex].size(); ++i) {
int to = adjList[currentVertex][i];
if (!used[to]) {
path[to] = path[currentVertex] + 1;
used[to] = true;
q.push(to);
for (int j = 0; j < K; j++) { //BAAAADDDDDD
if (to == playersStartPos[j]) {
res[ind][j] = path[to] + 1;
}
}
}
}
}
return 0;
}
void find()
{
for (int i = 0; i < K; i++) {
bfs(playersStartPos[i], i);
}
}
void write()
{
int min = N;
int one = 0;
int two = 0;
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
if (res[i][j] == 0) {
continue;
}
if (min > res[i][j]) {
min = res[i][j];
one = i;
two = j;
}
}
}
FILE* fp = fopen("output.txt", "w");
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
fprintf(fp, "%d ", res[i][j]);
}
fprintf(fp, "%c", '\n');
}
fprintf(fp, "%d %d\n", one, two);
//fclose(fp);
}
int main()
{
read();
find();
write();
return 0;
}
UPDATE WITH A MAP
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <map>
using namespace std;
vector<vector<int>> adjList;
int N = 0; //vertices quantity
int K = 0; //players quantity
map<int, int> playersStartPos;
//int playersStartPos[100];
int res[100][100];
void read()
{
FILE* fp = fopen("input2.txt", "r");
fscanf(fp, "%d", &N);
fscanf(fp, "%d", &K);
for (int i = 0; i < N; i++) {
int size = 0;
fscanf(fp, "%d", &size);
vector<int> adjacency(size);
for (int j = 0; j < size; j++) {
int to = 0;
fscanf(fp, "%d", &to);
adjacency[j] = to;
}
adjList.push_back(adjacency);
}
for (int player = 0; player < K; player++) {
int pos = 0;
fscanf(fp, "%d", &pos);
//cout << pos << " ";
playersStartPos[player] = pos;
}
/*for (int i = 0; i < adjList.size(); i++) {
cout << "From: " << i << " to: ";
for (int j = 0; j < adjList[i].size(); j++) {
cout << " " << adjList[i][j];
}
cout << endl;
}*/
//fclose(fp);
}
int bfs(int start, int ind)
{
queue<int> q;
vector<int> used(N, 0);
vector<int> path(N);
q.push(start);
used[start] = true;
path[start] = -1;
while (!q.empty()) {
int currentVertex = q.front();
q.pop();
for (size_t i = 0; i < adjList[currentVertex].size(); ++i) {
int to = adjList[currentVertex][i];
if (!used[to]) {
path[to] = path[currentVertex] + 1;
used[to] = 1;
q.push(to);
for (int j = 0; j < K; j++) {
auto it = playersStartPos.find(j);
if (it == playersStartPos.end()) continue;
if (to == it->second) {
//if (to == playersStartPos[j]) {
//cout << path[to] + 1 << endl;
res[ind][it->first] = path[to] + 1;
//res[ind][j] = path[to] + 1;
//break;
}
}
}
}
}
return 0;
}
void find()
{
for (int i = 0; i < K; i++) {
bfs(playersStartPos[i], i);
}
}
void write()
{
int min = N;
int one = 0;
int two = 0;
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
if (res[i][j] == 0) {
continue;
}
if (min > res[i][j]) {
min = res[i][j];
one = i;
two = j;
}
}
}
FILE* fp = fopen("output.txt", "w");
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
fprintf(fp, "%d ", res[i][j]);
}
fprintf(fp, "%c", '\n');
}
fprintf(fp, "%d %d\n", one, two);
//fclose(fp);
}
int main()
{
read();
find();
write();
return 0;
}
Here it is solution
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <map>
using namespace std;
vector<vector<int>> adjList;
int N = 0; //vertices quantity
int K = 0; //players quantity
map<int, int> playersStartPos;
int res[100][100];
void read()
{
FILE* fp = fopen("input.txt", "r");
fscanf(fp, "%d", &N);
fscanf(fp, "%d", &K);
for (int i = 0; i < N; i++) {
int size = 0;
fscanf(fp, "%d", &size);
vector<int> adjacency(size);
for (int j = 0; j < size; j++) {
int to = 0;
fscanf(fp, "%d", &to);
adjacency[j] = to;
}
adjList.push_back(adjacency);
}
for (int player = 0; player < K; player++) {
int vertex = 0;
fscanf(fp, "%d", &vertex);
playersStartPos[vertex] = player;
}
fclose(fp);
}
int bfs(int start, int ind)
{
queue<int> q;
vector<int> used(N, 0);
vector<int> path(N);
q.push(start);
used[start] = true;
path[start] = -1;
while (!q.empty()) {
int currentVertex = q.front();
q.pop();
for (size_t i = 0; i < adjList[currentVertex].size(); ++i) {
int to = adjList[currentVertex][i];
if (!used[to]) {
path[to] = path[currentVertex] + 1;
used[to] = 1;
q.push(to);
auto it = playersStartPos.find(to);
if (it == playersStartPos.end()) continue;
if (to == it->first) {
res[ind][it->second] = path[to] + 1;
}
}
}
}
return 0;
}
void find()
{
map<int, int>::iterator it;
for (it = playersStartPos.begin(); it != playersStartPos.end(); it++) {
bfs(it->first, it->second);
}
}
void write()
{
int min = N;
int one = 0;
int two = 0;
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
if (res[i][j] == 0) {
continue;
}
if (min > res[i][j]) {
min = res[i][j];
one = i;
two = j;
}
}
}
FILE* fp = fopen("output.txt", "w");
for (int i = 0; i < K; i++) {
for (int j = 0; j < K; j++) {
fprintf(fp, "%d ", res[i][j]);
}
fprintf(fp, "%c", '\n');
}
fprintf(fp, "%d %d\n", one, two);
fclose(fp);
}
int main()
{
read();
find();
write();
return 0;
}

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.