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.
Related
As I was practicing C++ today, I came across a code which finds the shortest path in an unweighted graph using BFS and outputs the length of the path and the vertices it travelled through.
I attempted to change up this code by introducing user input.
First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges.
The next M lines contain two integers, which indicates an undirected edge between two nodes.
I attempted to change the code in accordance to this, but I ran into a number of problems.
The first problem is that if I use gcc, the program will end after the for loop runs once in the main function.
However, if I use clang, the program runs fine. But there is an other issue and it relates to a very specific input.
The following input:
3 3
1 3
1 2
2 3
should return 1, but sometimes (specifically when I enter the input line by line) it returns the message: "Given source and destination are not connected". It is completely random.
The code is below:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[]);
void printShortestDistance(vector<int> adjList[], int s, int dest, int numOfVertices);
int main()
{
int numOfVertices, numOfEdges;
cin >> numOfVertices >> numOfEdges;
vector<int> adjList[numOfVertices];
if (2 <= numOfVertices && numOfVertices <= 1e5 && 1 <= numOfEdges && numOfEdges <= 1e5)
{
for (int i = 0; i < numOfEdges; i++)
{
int node1, node2;
cin >> node1 >> node2;
if ((1 <= node1) && (1 <= node2) && (node1 <= numOfVertices) && (node2 <= numOfVertices) && (node1 != node2))
{
adjList[node1].push_back(node2);
adjList[node2].push_back(node1);
}
else{ return EXIT_FAILURE; }
}
int source = 1;
int dest = numOfVertices;
printShortestDistance(adjList, source, dest, numOfVertices);
}
}
void printShortestDistance(vector<int> adjList[], int source, int dest, int numOfVertices)
{
int pred[numOfVertices];
int dist[numOfVertices];
if (BFS(adjList, source, dest, numOfVertices, pred, dist) == false)
{
cout << "Given source and destination are not connected";
return;
}
vector<int> path;
int crawl = dest;
path.push_back(crawl);
while (pred[crawl] != -1)
{
path.push_back(pred[crawl]);
crawl = pred[crawl];
}
cout << "Shortest path length is : " << dist[dest];
cout << "\nPath is::\n";
for (int i = path.size() - 1; i >= 0; i--)
cout << path[i] << " ";
}
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[])
{
list<int> queue;
bool visited[numOfVertices];
for (int i = 0; i < numOfVertices; i++)
{
visited[i] = false;
dist[i] = INT_MAX;
pred[i] = -1;
}
visited[source] = true;
dist[source] = 0;
queue.push_back(source);
while (!queue.empty())
{
int u = queue.front();
queue.pop_front();
for (int i = 0; i < adjList[u].size(); i++)
{
if (visited[adjList[u][i]] == false)
{
visited[adjList[u][i]] = true;
dist[adjList[u][i]] = dist[u] + 1;
pred[adjList[u][i]] = u;
queue.push_back(adjList[u][i]);
// We stop BFS when we find
// destination.
if (adjList[u][i] == dest)
return true;
}
}
}
return false;
}
"First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges."
This is not a good idea. Humans are terrible at counting, while computers are pretty good at it. So do not make your users count the vertices and edges - they will often get it wrong and cause chaos.
Just input the start and ending nodes of an edge. If a node is already present in the data structure, connect it. If node not already present then add it and then connect it.
You will have much happier users!
I see that you have decided to store your graph in an adjacency list. This is a perfectly reasonable idea, but the snag is that it is quite a challenge to code. This seems to be your first attempt to code a graph theory problem, so I recommend that you use an adjacency matrix instead since it is much easier to code.
For small graphs the difference is insignificant, so you need only consider switching to the more complicate adjacency list when you are working with enormous graphs ( many thousands of nodes )
Remember that vectors in C++ are 0-based.
In your example, numOfVertices and numOfEdges are both 3, so node 3 will lead to out-of-bound access. Either change your input to 0-based node numbers or use node1-1 and node2-1.
See also
Vector going out of bounds without giving error
and the accepted answer.
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;
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.
A problem involves a depth first search in a directed graph to find all the nodes that can be reached from a particular node. The solution given below is giving a wrong result on codechef. But I cannot find any test case for which this might produce a different result that the usual DFS algorithm would.
I know I can directly implement the correct algorithm to get the right result but I want to learn why my solution was incorrect so that I won't repeat it in future. Please help me identify whats wrong with this solution. The code is commented to explain my approach
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long int lli;
vector <lli> g[1000+5]; // the adjacency list 1 indexed
void dfs(lli j, lli i);
int main(){
lli n, m, k, a, b;
// n = number of nodes
// m = number of relations
// k = multiplication factor
cin >> n >> m >> k;
while(m--){
// a,b means a is dependent upon b (directed graph)
cin >> a >> b;
g[a].push_back(b);
}
for(lli j = 1; j <= n; j++)
for(lli i = 0; i < g[j].size(); i++){
dfs(j, g[j][i]); // adds dependencies of g[j][i]
// to adjacency list of j
}
// ans is the minimum no of nodes dependent on a particular node
lli ans = g[1].size();
for(lli i = 1; i <= n; i++){
if(g[i].size() < ans)
ans = g[i].size();
}
cout << (ans+1)*k <<"\n";
}
void dfs(lli j, lli i){
// adding dependencies of a node to itself
// would result in an infinite loop?
if(i != j){
for(lli k = 0; k < g[i].size(); k++){
// a node is not dependent on itself
if(g[i][k]!=j && find(g[j].begin(), g[j].end(), g[i][k])==g[j].end()){
g[j].push_back(g[i][k]);
dfs(j, g[i][k]);
}
}
}
}`
The link for the problem : problem
link for correct solution: correct solution
Your problem is that you are not aware of multi-edges which are possible with the given problem constrains, otherwise it looks correct. Take a look at this test case:
2 4 1
1 2
1 2
2 1
2 1
Your program will return 3, but there are only 2 vertices!
Having said that, I would like to add, that I disagree with the sample solution: It says the running time would be O(N^2) which is not true, because it starts N dfs every one with costs of O(N+M) thus resulting in O(N*(N+M)) with N=10^3 and M=10^6 there is no change to be in the time limit of 0.01 seconds!
Actually, this problem can be solved in O(N+M) using algorithms for detecting strongly connected components.
Here my tryings, and copypastings. But what i must write to find biconnectedcomponent (called block)?
#include <fstream>
#include <vector>
using namespace std;
ifstream cin ("test3.txt");
ofstream cout ("output.txt");
const int l = 6;
int G[l][l];
int MAXN;
int used[l];
int number[l], low[l], counter = 1, kids = 0;
vector <int> block[l];
void BiComp(int curr, int prev) {
int kids = 0;
low[curr] = number[curr] = counter++;
used[curr] = 1;
for(int i = 0; i < MAXN; i++) {
if(G[curr][i] == 1) {
if (i != prev) {
if (used[i] == 0) {
kids++;
block[0].push_back(curr);
block[0].push_back(i);
BiComp(i, curr);
low[curr] = min(low[curr], low[i]);
if(low[i] >= number[curr] && (prev != -1 || kids >= 2)) {
cout << "tochka " << curr + 1 << endl;
}
} else {
block[0].push_back(i);
block[0].push_back(prev);
cout<<block<<endl;
low[curr] = min(low[curr], number[i]);
}
}
}
}
}
void main()
{
MAXN = 6;
for (int i = 0; i < MAXN; i++)
{
for (int j = 0; j < MAXN; j++)
{
cin >> G[i][j];
cout << G[i][j] << " ";
}
cout << endl;
}
//for (int i = 0; i < MAXN; i++) {
//if (number[i] == 0) {
BiComp(0, -1);
//}
//}
}
How can i find by this code, finding cutpoints at the same time blocks???
In graph theory, a biconnected component (or 2-connected component) is a maximal biconnected subgraph.
Ok what comes to my mind is a very brute-force approach that isn't going to scale well, but I also remember reading that finding biconnected components is in fact a hard problem, computationally, so let's just start with it and then see if there's optimizations to be done.
Given a set of N nodes, check for each possible subset of nodes whether they form a biconnected component. Typically, you'll want the biggest component available, so just start with the whole graph, then with all subgraphs of N-1 nodes, N-2, and so on. As soon as you find one solution, you'll know you have found one of the biggest possible size and you can quite. Still, you'll end up checking 2^N subgraphs in the worst case. So start with a loop constructing your graphs to be tested.
To find out if a given graph with K nodes is a biconnected component, loop over all K*(K-1)/2 pairs of nodes and find out if there are two independent paths between them.
In order to find out if two nodes i and j are biconnected, first find all paths between them. For each path, find out if there is an alternative connection to that path. If you find one, you're done for that pair. If not, you've found proof that the graph you're looking at is not biconnected and you can break from all loops but the outer one and test the next graph.
In order to see if there is an alternative connection between i and j, take out all edges you used in the first path, and see if you can find another one. If you can, you're fine with i and j. If you can't, continue with the next path in the initial list of paths you found. If you reach the end of your list of paths without finding one for which an alternative exists when taking out the involved edges, the two nodes are not biconnected and hence the whole graph isn't.
There is a linear run time algorithm for finding all cut points (or cut vertices or articulation points) in a given graph using Depth First Search.
Once you found all the cut points, it's easy to find all of the bicomponents.