Currently trying to implement dijkstra's algorithm in C++ by the use of an adjacency list in a text file read into a map object. The map is initialized as:
map<int, vector<pair<int, int>>> = adjList;
Sample text file input:
1 2,1 8,2
2 1,1 3,1
3 2,1 4,1
4 3,1 5,1
5 4,1 6,1
6 5,1 7,1
7 6,1 8,1
8 7,1 1,2
Where the key is a vertex, and the x values of the pairs in the vector are connected to the key vertex. The y values are the path distances. I pass that map into my dijkstra function, where I initialize a vector for shortest distances and a vector for storing visited vertices. My loop is where things start going wrong, as I get outputs of zeroes and very large numbers. Here's my code:
//checks if vertex has been visited or not
bool booler(int vertex, vector<int> visited){
bool booly;
if(find(visited.begin(), visited.end(), vertex) != visited.end()){
booly = true;
}
else{
booly = false;
}
return booly;
}
//checks vector for the shortest distance vertex
int minDist(vector<int> distances, vector<int> visited){
int minDist = 1000000;
int index;
for(int v = 0; v < distances.size(); v++){
if(booler(v, visited) == false && distances[v] < minDist){
minDist = distances[v];
index = v;
}
}
return index;
}
void dijkstra(int source, map<int, vector<pair<int, int>>> adjList, int vSize){
vector<int> distances(vSize, 1000000);
vector<int> visited = {};
distances[source] = 0;
for(int c = 0; c < distances.size(); c++){
int u = minDist(distances, visited);
visited.push_back(u);
for(int v = 1; v < distances.size(); v++){
for(int s = 0; s < adjList[u].size(); s++){
//updates distances based on v connection to u
if(booler(v, visited) == false && distances[u] < 1000000 && adjList[u][s].second + distances[u] < distances[v]){
distances[v] = distances[u] + adjList[u][v].second;
}
}
}
}
//prints out shortest path
for(int x = 0; x < distances.size(); x++){
cout << distances[x] << " " << endl;
}
}
I haven't been able to fix this error, any help would be greatly appreciated!
Here is an implement how to use dijkstra.
https://www.quora.com/What-is-the-most-simple-efficient-C++-code-for-Dijkstras-shortest-path-algorithm
It is my solution for your problem:
#include "bits/stdc++.h"
using namespace std;
map<int, vector<pair<int, int> > > mp;
void addEdge(int u, int v, int dist) {
mp[u].push_back(make_pair(v, dist));
}
void startDijkstra(int u) {
vector<int> dist(1e2 + 1, 1e9);
set<pair<int, int> > st;
st.insert(make_pair(0, u));
dist[u] = 0;
while (!st.empty()) {
pair<int, int> now = *st.begin();
st.erase(st.begin());
int v = now.second;
int w = now.first;
const vector<pair<int, int> > &edges = mp[v];
for (const pair<int, int> &to : edges) {
if (w + to.second < dist[to.first]) {
st.erase(make_pair(dist[to.first], to.first));
dist[to.first] = w + to.second;
st.insert(make_pair(dist[to.first], to.first));
}
}
}
for (int i = 1; i <= 8; i++) {
cout << i << ' ' << dist[i] << endl;
}
}
int main() {
addEdge(1, 2, 1);
addEdge(1, 8, 2);
addEdge(2, 1, 1);
addEdge(2, 3, 1);
addEdge(3, 2, 1);
addEdge(3, 4, 1);
addEdge(4, 3, 1);
addEdge(4, 5, 1);
addEdge(5, 4, 1);
addEdge(5, 6, 1);
addEdge(6, 5, 1);
addEdge(6, 7, 1);
addEdge(7, 6, 1);
addEdge(7, 8, 1);
addEdge(8, 9, 1);
addEdge(8, 1, 2);
startDijkstra(1);
return 0;
}
Related
I want to implement a function that is able to translate(rotate) the sequence of a 2d array to the desired destination index. A, B, and C represents the length of the sequence. Source is the beginning of the sequence to be rotated. Source in the example below would be A. Dst is the index of the beginning of the target moving. Input/Output example: Before:
double A[][2] = { {0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7} };
^dst A B C
Calling function translate(A, 8, 5, 3, 1);
{ {0,0}, {5,5}, {6,6}, {7,7}, {1,1}, {2,2}, {3,3}, {4,4} };
A B C
When I run my code, the final index doesn't make it to the output array. What am I missing on the conditions?
/*
A-list of locations; 2d array
n- number of cities
src-index of the beginning of the sequence to be moved
len- length of sequence to translate
dst-index of the beginning of the target of moving
*/
void translate ( double A[][2], int n, int src, int len, int dst ) {
vector<vector<int>> variable;
variable.resize(n);
//to move sequence
for(int i = 0; i <= n - 1; i++) {
int source_index = (src + i)%(n - 1);
//cout << source_index << endl;
int destination_index = (dst - 1 + i)%(n - 1) + 1;
vector<int> variable2;
variable2.push_back(A[source_index][0]);
variable2.push_back(A[source_index][1]);
variable.at(destination_index) = variable2;
}
//get vector into array
for(int i = 1; i < n; i++){
A[i][0] = variable[i][0];
A[i][1] = variable[i][1];
}
}
My output:
(0, 0),(5, 5),(6, 6),(0, 0),(1, 1),(2, 2),(3, 3),(4, 4)
After working through it, I think I finally got it.
void translate ( double A[][2], int n, int src, int len, int dst ) {
vector<vector<int>> variable;
variable.resize(n);
//to move sequence
for(int i = 0; i <= n - 1; i++) {
int source_index = (src - 1 + i)%(n - 1) + 1;
//cout << source_index << endl;
int destination_index = (dst - 1 + i)%(n - 1) + 1;
vector<int> variable2;
variable2.push_back(A[source_index][0]);
variable2.push_back(A[source_index][1]);
variable.at(destination_index) = variable2;
}
//get vector into array
for(int i = 1; i < n; i++){
A[i][0] = variable[i][0];
A[i][1] = variable[i][1];
}
}
I have a shortest path problem:
Given a graph with n vertices, find the shortest path(as in number of edges taken, not edge weight) from vertex 1 to vertex n, if there are multiple of those paths, take the one with the least lexicographical order of its edge weights.
The Input consists of n and m, n vertices and m edges (2 <= n <= 100.000; 1 <= m <= 200.000) followed by the m edges.
Between 2 vertices can be multiple edges. It's my first time working with C++, coming from Java.
My current input/main looks like this:
ios::sync_with_stdio(false);
int n, m, v1, v2, w;
vector<string> outvec;
while (infile >> n >> m) {
int k = 0;
for (int i = 0; i < m; i++) {
infile >> v1 >> v2 >> w;
//TODO Only add smallest edge between 2 vertices
if (v1 != v2) {
adj[v1].push_back(make_pair(v2, w));
adj[v2].push_back(make_pair(v1, w));
}
}
dijkstra(n + 1);
string outs;
while (n != 1) {
outs.insert(0, to_string(col[n]) + " ");
n = previ[n];
k++;
}
outs = outs.substr(0, outs.length() - 1);
outvec.push_back(to_string(k).append("\n").append(outs).append("\n"));
for (auto& v : adj) {
v.clear();
}
}
Where adj represents the adjacency list, an array of vector<pair<int,int>> to be exact.
After all that I'm using Dijkstra's Algorithm for the shortest path with the 2 metrics mentioned above. But it's still too slow for the needed cases.
My idea was, to reduce the maximum number of edges between two vertices to one, with the minimum weight of all edges before, so that Dijkstra won't need to traverse all edges between two vertices.
Is there an efficient way to achieve my goal? And is Dijkstra the way to go here?
So my problem is my performance in runtime, so here is my current implementation on dijkstra as well:
void dijkstra(int m) {
for (int i = 0; i < m; i++) {
dis[i] = INT_MAX;
col[i] = INT_MAX;
previ[i] = -1;
vis[i] = false;
}
dis[1] = 0;
priority_queue<pair<int, double>, vector<pair<int, double> >, cmp> q;
q.push(make_pair(1, 0));
while (!q.empty()) {
pair<int, double> currPair = q.top();
q.pop();
int currVertex = currPair.first;
double currWeight = currPair.second;
if (vis[currVertex]) {
continue;
}
else if (currVertex == m - 1) {
break;
}
vis[currVertex] = true;
for (int i = 0; i < adj[currVertex].size(); i++) {
int nextVertex = adj[currVertex][i].first;
int nextEdgeCol = adj[currVertex][i].second;
int currEdgeCol = col[nextVertex];
if (!vis[nextVertex]) {
pair<int, int> newP;
if (currWeight + 1 < dis[nextVertex]) {
previ[nextVertex] = currVertex;
dis[nextVertex] = currWeight + 1;
col[nextVertex] = nextEdgeCol;
newP = make_pair(nextVertex, dis[nextVertex]);
}
else if (currWeight + 1 == dis[nextVertex]) {
if (col[nextVertex] > nextEdgeCol) {
previ[nextVertex] = currVertex;
dis[nextVertex] = currVertex + 1;
col[nextVertex] = nextEdgeCol;
newP = make_pair(nextVertex, dis[nextVertex]);
}
}
q.push(newP);
}
}
}
}
For further information on the problem look here.
I am trying to use the Boost implementation of Boykov-Kolmogorov max-flow algorithm.
Here is how I do it:
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
boost::no_property,
boost::property<boost::edge_index_t, std::size_t> > GraphType;
typedef boost::graph_traits<GraphType>::vertex_descriptor VertexDescriptor;
typedef boost::graph_traits<GraphType>::edge_descriptor EdgeDescriptor;
typedef boost::graph_traits<GraphType>::vertices_size_type VertexIndex;
typedef boost::graph_traits<GraphType>::edges_size_type EdgeIndex;
int numberOfVertices; //The number of vertices in my graph
std::vector<std::set<int>> neighbours(numberOfVertices);
// I fill the neighbours vector with information about neighbouring vertices
int sourceId = numberOfVertices;
int sinkId = sourceId + 1;
std::size_t size = 0;
for (int i = 0; i < neighbours.size(); i++) {
size += neighbours[i].size();
}
std::vector<float> sourceWeights(numberOfVertices);
std::vector<float> sinkWeights(numberOfVertices);
for (int i = 0; i < numberOfVertices; i++) {
sourceWeights[i] = 1.0f;
sinkWeights[i] = 1.0f;
}
std::vector<int> groups(numberOfVertices, 0);
std::vector<float> capacity(3 * numberOfVertices + size, 0.0f);
std::vector<EdgeDescriptor> reverseEdges(3 * numberOfVertices + size);
GraphType graph;
for (int i = 0; i < numberOfVertices; i++) {
boost::add_vertex(graph);
}
std::vector<std::pair<int, int>> edges((size - numberOfVertices) / 2);
int countEdges = 0;
for (int i = 0; i < neighbours.size(); i++) {
for (int c : neighbours[i]) {
if (i < c) {
edges[countEdges] = (std::pair<int, int>(i, c));
countEdges++;
}
}
}
//I create the edges as std::pair<int,int>
//in order to add them to the graph after with the corresponding weights
for (int i = 0; i < edges.size(); i++) {
float weight = 1.0f;
int nextEdgeId = 2 * i;
EdgeDescriptor edge;
bool inserted;
boost::tie(edge, inserted) = boost::add_edge(boost::vertex(edges[i].first, graph), boost::vertex(edges[i].second, graph), nextEdgeId, graph);
if (!inserted)
{
std::cerr << "Not inserted!" << std::endl;
}
EdgeDescriptor reverseEdge = boost::add_edge(boost::vertex(edges[i].second, graph), boost::vertex(edges[i].first, graph), nextEdgeId + 1, graph).first;
reverseEdges[nextEdgeId] = reverseEdge;
reverseEdges[nextEdgeId + 1] = edge;
capacity[nextEdgeId] = weight;
capacity[nextEdgeId + 1] = weight;
}
VertexDescriptor sourceVertex = boost::vertex(sourceId, graph);
VertexDescriptor sinkVertex = boost::vertex(sinkId, graph);
for (int i = 0; i < numberOfVertices; i++) {
int nextEdgeId = 2 * edges.size() + 4 * i;
EdgeDescriptor edge;
bool inserted;
boost::tie(edge, inserted) = boost::add_edge(boost::vertex(i, graph), sourceVertex, nextEdgeId, graph);
if (!inserted)
{
std::cerr << "Not inserted!" << std::endl;
}
EdgeDescriptor reverseEdge = boost::add_edge(sourceVertex, boost::vertex(i, graph), nextEdgeId + 1, graph).first;
reverseEdges[nextEdgeId] = reverseEdge;
reverseEdges[nextEdgeId + 1] = edge;
capacity[nextEdgeId] = sourceWeights[i];
capacity[nextEdgeId + 1] = sourceWeights[i];
int nextEdgeId2 = nextEdgeId + 2;
EdgeDescriptor edge2;
bool inserted2;
boost::tie(edge2, inserted2) = boost::add_edge(boost::vertex(i, graph), sinkVertex, nextEdgeId2, graph);
if (!inserted2)
{
std::cerr << "Not inserted!" << std::endl;
}
EdgeDescriptor reverseEdge2 = boost::add_edge(sinkVertex, boost::vertex(i, graph), nextEdgeId2 + 1, graph).first;
reverseEdges[nextEdgeId2] = reverseEdge2;
reverseEdges[nextEdgeId2 + 1] = edge2;
capacity[nextEdgeId2] = sinkWeights[i];
capacity[nextEdgeId2 + 1] = sinkWeights[i];
}
std::vector<float> residual_capacity(boost::num_edges(graph), 0.0f);
//I launch the algorithm by using all the vectors I defined previously
boost::boykov_kolmogorov_max_flow(graph,
boost::make_iterator_property_map(&capacity[0], boost::get(boost::edge_index, graph)),
boost::make_iterator_property_map(&residual_capacity[0], boost::get(boost::edge_index, graph)),
boost::make_iterator_property_map(&reverseEdges[0], boost::get(boost::edge_index, graph)),
boost::make_iterator_property_map(&groups[0], boost::get(boost::vertex_index, graph)),
boost::get(boost::vertex_index, graph),
sourceVertex,
sinkVertex);
I am using this code on several images (around 100). There's a lot of preprocessing on the images to extract clusters that will act as the vertices of my graph and the connectivity information between these clusters.
The code runs fine on most of the images. When I launch my program, it runs on 10 images perfectly but then, on the 11th image, for no apparent reason, it crashes with the message
Unhandled exception at 0x00007FF9B52DE6FC (ntdll.dll) in Program.exe: 0xC0000374: A heap has been corrupted (parameters: 0x00007FF9B53322B0).
It also crashes directly if I only run it on the 11th image.
The call stack is really long (thanks Boost for all those templates) so I won't post it here but the application is failing when calling boost::boykov_kolmogorov_max_flow. If I remove the line where I call this function, the program runs perfectly on all images (even the 11th one).
I am running this program in Visual Studio 2013 on a Windows 10 64-bit machine with 64Gb RAM.
So my question is, what could be the cause of this heap corruption error that only shows up on certain images (which, in this case, only means different number of vertices and neighbours information since I set the weights at 1.0 everywhere) ?
I have the adjacency matrix of a graph. I wish to calculate the number of hamiltonian paths.
I know the brute force approach tests all N! permutations. However, I am unable to code it, I tried searching but couldn't find a possible approach.
I was looking for help for the simple brute force approach.
Thanks.
See my implementation I just did:
Also check this Hamilton cycle implementation to get some insights how it's done.
#include <stdio.h>
#include <stdbool.h>
#define NUM_VERTICES 4
bool graph[NUM_VERTICES][NUM_VERTICES] = {
{0, 1, 0, 1},
{1, 0, 1, 1},
{0, 1, 0, 0},
{1, 1, 0, 0},
};
int parent[NUM_VERTICES];
bool fin_hp_r(int v, int n)
{
// If all vertices are connected
if (n == NUM_VERTICES)
return true;
// For all neighbours
for (int i = 0; i < NUM_VERTICES; ++i)
if (graph[v][i] && parent[i] == -1)
{
parent[i] = v;
if (fin_hp_r(i, n + 1))
return true;
parent[i] = -1;
}
return false;
}
bool find_hamilton_path()
{
memset(parent, -1, sizeof(int) * NUM_VERTICES);
for (int i = 0; i < NUM_VERTICES; ++i)
{
parent[i] = i;
if (fin_hp_r(i, 1))
return true;
parent[i] = -1;
}
}
int main(void) {
find_hamilton_path();
for (int i = 0; i < NUM_VERTICES; ++i)
printf ("%d -> %d\n", parent[i], i);
return 0;
}
And this one for counting number of all Hamilton paths:
#include <stdio.h>
#include <stdbool.h>
#define NUM_VERTICES 4
bool graph[NUM_VERTICES][NUM_VERTICES] = {
{0, 1, 0, 1},
{1, 0, 1, 1},
{0, 1, 0, 0},
{1, 1, 0, 0},
};
int parent[NUM_VERTICES];
long long cnt_fin_hp_r(int v, int n)
{
// If all vertices are connected
if (n == NUM_VERTICES)
return 1;
// For all neighbours
long long res = 0;
for (int i = 0; i < NUM_VERTICES; ++i)
if (graph[v][i] && parent[i] == -1)
{
parent[i] = v;
res += cnt_fin_hp_r(i, n + 1);
parent[i] = -1;
}
return res;
}
long long find_hamilton_path_number()
{
memset(parent, -1, sizeof(int) * NUM_VERTICES);
long long res = 0;
for (int i = 0; i < NUM_VERTICES; ++i)
{
parent[i] = i;
res += cnt_fin_hp_r(i, 1);
parent[i] = -1;
}
return res;
}
int main(void) {
printf("%lld\n", find_hamilton_path_number());
return 0;
}
This is a problem from an ongoing contest
https://www.codechef.com/JAN16/problems/SEAKAM
I am trying to a C++ implementation of this knapsack problem using branch and bounding. There is a Java version on this website here: Implementing branch and bound for knapsack
I'm trying to make my C++ version print out the 90 that it should, however it's not doing that, instead, it's printing out 5.
Does anyone know where and what the problem may be?
#include <queue>
#include <iostream>
using namespace std;
struct node
{
int level;
int profit;
int weight;
int bound;
};
int bound(node u, int n, int W, vector<int> pVa, vector<int> wVa)
{
int j = 0, k = 0;
int totweight = 0;
int result = 0;
if (u.weight >= W)
{
return 0;
}
else
{
result = u.profit;
j = u.level + 1;
totweight = u.weight;
while ((j < n) && (totweight + wVa[j] <= W))
{
totweight = totweight + wVa[j];
result = result + pVa[j];
j++;
}
k = j;
if (k < n)
{
result = result + (W - totweight) * pVa[k]/wVa[k];
}
return result;
}
}
int knapsack(int n, int p[], int w[], int W)
{
queue<node> Q;
node u, v;
vector<int> pV;
vector<int> wV;
Q.empty();
for (int i = 0; i < n; i++)
{
pV.push_back(p[i]);
wV.push_back(w[i]);
}
v.level = -1;
v.profit = 0;
v.weight = 0;
int maxProfit = 0;
//v.bound = bound(v, n, W, pV, wV);
Q.push(v);
while (!Q.empty())
{
v = Q.front();
Q.pop();
if (v.level == -1)
{
u.level = 0;
}
else if (v.level != (n - 1))
{
u.level = v.level + 1;
}
u.weight = v.weight + w[u.level];
u.profit = v.profit + p[u.level];
u.bound = bound(u, n, W, pV, wV);
if (u.weight <= W && u.profit > maxProfit)
{
maxProfit = u.profit;
}
if (u.bound > maxProfit)
{
Q.push(u);
}
u.weight = v.weight;
u.profit = v.profit;
u.bound = bound(u, n, W, pV, wV);
if (u.bound > maxProfit)
{
Q.push(u);
}
}
return maxProfit;
}
int main()
{
int maxProfit;
int n = 4;
int W = 16;
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
cout << knapsack(n, p, w, W) << endl;
system("PAUSE");
}
I think you have put the profit and weight values in the wrong vectors. Change:
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
to:
int w[4] = {2, 5, 10, 5};
int p[4] = {40, 30, 50, 10};
and your program will output 90.
I believe what you are implementing is not a branch & bound algorithm exactly. It is more like an estimation based backtracking if I have to match it with something.
The problem in your algorithm is the data structure that you are using. What you are doing is to simply first push all the first levels, and then to push all second levels, and then to push all third levels to the queue and get them back in their order of insertion. You will get your result but this is simply searching the whole search space.
Instead of poping the elements with their insertion order what you need to do is to branch always on the node which has the highest estimated bound. In other words you are always branching on every node in your way regardless of their estimated bounds. Branch & bound technique gets its speed benefit from branching on only one single node each time which is most probable to lead to the result (has the highest estimated value).
Example : In your first iteration assume that you have found 2 nodes with estimated values
node1: 110
node2: 80
You are pushing them both to your queue. Your queue became "n2-n1-head" In the second iteration you are pushing two more nodes after branching on node1:
node3: 100
node4: 95
and you are adding them to you queue as well("n4-n3-n2-head". There comes the error. In the next iteration what you are going to get will be node2 but instead it should be node3 which has the highest estimated value.
So if I don't miss something in your code both your implementation and the java implementation are wrong. You should rather use a priority queue (heap) to implement a real branch & bound.
You are setting the W to 16, so the result is 5. The only item you can take into the knapsack is item 3 with profit 5 and weight 10.
#include <bits/stdc++.h>
using namespace std;
struct Item
{
float weight;
int value;
};
struct Node
{
int level, profit, bound;
float weight;
};
bool cmp(Item a, Item b)
{
double r1 = (double)a.value / a.weight;
double r2 = (double)b.value / b.weight;
return r1 > r2;
}
int bound(Node u, int n, int W, Item arr[])
{
if (u.weight >= W)
return 0;
int profit_bound = u.profit;
int j = u.level + 1;
int totweight = u.weight;
while ((j < n) && (totweight + arr[j].weight <= W))
{
totweight = totweight + arr[j].weight;
profit_bound = profit_bound + arr[j].value;
j++;
}
if (j < n)
profit_bound = profit_bound + (W - totweight) * arr[j].value /
arr[j].weight;
return profit_bound;
}
int knapsack(int W, Item arr[], int n)
{
sort(arr, arr + n, cmp);
queue<Node> Q;
Node u, v;
u.level = -1;
u.profit = u.weight = 0;
Q.push(u);
int maxProfit = 0;
while (!Q.empty())
{
u = Q.front();
Q.pop();
if (u.level == -1)
v.level = 0;
if (u.level == n-1)
continue;
v.level = u.level + 1;
v.weight = u.weight + arr[v.level].weight;
v.profit = u.profit + arr[v.level].value;
if (v.weight <= W && v.profit > maxProfit)
maxProfit = v.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
v.weight = u.weight;
v.profit = u.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
}
return maxProfit;
}
int main()
{
int W = 55; // Weight of knapsack
Item arr[] = {{10, 60}, {20, 100}, {30, 120}};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Maximum possible profit = "
<< knapsack(W, arr, n);
return 0;
}
**SEE IF THIS HELPS**