How to speed up this box stacking variation? - c++

I have a box stacking-like problem: Given boxes of 3 dimensions find the longest sequence (sorted from largest to smallest box) of boxes so that each box can be nested in another like a nesting doll. We can rotate boxes in multiples of 90°. I solved this problem by connecting each box to every box which can be nested in it and then I applied DFS-like algorithm to find the longest path from infinite large box. But I would like to speed up this algorithm as well as reduce memory using. Any suggestions how can I do it?
#include <iostream>
#include <list>
using namespace std;
struct Box {
int h;
int w;
int l;
};
// Sort box dimensions from smallest to largest so then we can easily decide if some box can fit into another.
Box createBox(int h, int w, int l)
{
if (h > l) {
swap(h, l);
}
if (h > w) {
swap(h, w);
}
if (w > l) {
swap(w, l);
}
struct Box box = { h, w, l };
return box;
}
// Does the second box fit in the first?
bool doesFit(Box box1, Box box2)
{
if (box1.h > box2.h &&
box1.w > box2.w &&
box1.l > box2.l) {
return true;
}
return false;
}
class Graph {
int V;
void findLongestPathUtil(int v, int path[], int& path_index);
vector<Box> boxes;
list<int> longest_path;
public:
Graph(int V);
list<int>* adj;
void addEdge(Box b);
int lpath_index = 0;
void linkVertices();
list<int> findLongestPath(int start);
};
Graph::Graph(int V)
{
this->V = V;
list<int> lpath(V, -1);
longest_path = lpath;
adj = new list<int>[V];
}
void Graph::addEdge(Box b)
{
boxes.push_back(b);
}
// Each directed arc from node A to node B indicates that the corresponding Box A holds Box B
void Graph::linkVertices()
{
for (int i = 0; i < V; i++) {
for (int k = 0; k < V; k++) {
if (doesFit(boxes[i], boxes[k])) {
adj[i].push_back(k);
}
}
}
}
list<int> Graph::findLongestPath(int start)
{
int* path = new int[V];
int path_index = 0;
this->findLongestPathUtil(start, path, path_index);
return this->longest_path;
}
void Graph::findLongestPathUtil(int v, int path[], int& path_index) {
path[path_index] = v;
path_index++;
if (path_index > lpath_index) {
int k = 0;
for (list<int>::iterator i = longest_path.begin(); i != longest_path.end(); ++i) {
if (k >= path_index)
break;
*i = path[k];
k += 1;
}
lpath_index = path_index;
}
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i) {
findLongestPathUtil(*i, path, path_index);
}
path_index--;
}
int main()
{
int n;
cin >> n;
Graph g(n + 1);
for (int i = 0; i < n; i++) {
int w, l, h;
cin >> w >> l >> h;
g.addEdge(createBox(w, l, h));
}
g.addEdge(createBox(INT_MAX, INT_MAX, INT_MAX)); // Infinite box
g.linkVertices();
list<int> path = g.findLongestPath(n);
cout << g.lpath_index-1 << endl; // Subtract one because path has also the infinite box
int k = 0;
for (auto i : path)
{
if (k >= g.lpath_index)
break;
if (k != 0)
cout << i << endl;
k += 1;
}
return 0;
}
To add understanding of the problem I also add example input/output:
10 # number of boxes
8 10 9 # length, width, height of 1. box...
9 7 10
9 10 8
7 7 9
6 1 5
2 6 4
4 5 4
6 7 10
8 6 1
3 10 10
Output:
3 # number of boxes in the nesting doll
0 # index of box in input...
3
4

There's a simpler, faster algorithm for solving this problem:
First, rotate all the boxes so that h is the longest dimension, then w, then d. Then, sort all the boxes by (h,w,d). Note that any box in this list can only contain boxes that occur earlier in the list.
For each box, calculate the largest number of boxes that can nest inside, and make a link to the largest box in the largest nesting chain. This is easy to do for each box just by examining the already-calculated results for the smaller boxes that fit inside. This step dominates the time taken by the algorithm, requiring O(N2) time.
Finally, find the box with the longest chain, and follow the links to generate the list of boxes in the chain.

Related

Finding heaviest path (biggest sum of weights) of an undirected weighted graph? Bellman Ford --

There's a matrix, each of its cell contains an integer value (both positive and negative). You're given an initial position in the matrix, now you have to find a path that the sum of all the cells you've crossed is the biggest. You can go up, down, right, left and only cross a cell once.
My solution is using Bellman Ford algorithm: Let's replace all the values by their opposite number, now we've just got a new matrix. Then, I create an undirected graph from the new matrix, each cell is a node, stepping on a cell costs that cell's value - it's the weight. So, I just need to find the shortest path of the graph using Bellman-Ford algorithm. That path will be the longest path of our initial matrix.
Well, there's a problem. The graph contains negative cycles, also has too many nodes and edges. The result, therefore, isn't correct.
This is my code:
Knowing that xd and yd is the initial coordinate of the robot.
void MatrixToEdgelist()
{
int k = 0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
int x = (i - 1) * n + j;
int y = x + 1;
int z = x + n;
if (j<n)
{
edges.push_back(make_tuple(x, y, a[i][j+1]));
}
if (i<n)
{
edges.push_back(make_tuple(x, z, a[i+1][j]));
}
}
}
void BellmanFord(Robot r){
int x = r.getXd();
int y = r.getYd();
int z = (x-1)*n + y;
int l = n*n;
int distance[100];
int previous[100]{};
int trace[100];
trace[1] = z;
for (int i = 1; i <= l; i++) {
distance[i] = INF;
}
distance[z] = a[x][y];
for (int i = 1; i <= l-1; i++) {
for (auto e : edges) {
int a, b, w;
tie(a, b, w) = e;
//distance[b] = min(distance[b], distance[a]+w);
if (distance[b] < distance[a] + w)// && previous[a] != b)
{
distance[b] = distance[a] + w;
previous[b] = a;
}
}
}
//print result
int Max=INF;
int node;
for (int i=2;i<=l;i++)
{
if (Max < distance[i])
{
Max = distance[i];
node = i;
}
}
if (Max<0)cout << Max << "\n";
else cout << Max << "\n";
vector<int> ans;
int i = node;
ans.push_back(i);
while (i != z)
{
i = previous[i];
ans.push_back(i);
}
for (int i=ans.size()-1;i>=0;i--)
{
int x, y;
if (ans[i] % n == 0)
{
x = ans[i] / n;
y = n;
}
else{
x = ans[i] / n + 1;
y = ans[i] - (( x - 1 ) * n);
}
cout << x << " " << y << "\n";
}
}
Example matrix
The result
Clearly that the distance should have continued to update, but it doesn't. It stops at the final node.
"Let's replace all the values by their opposite number"
Not sure what you mean by an opposite number. Anyway, that is incorrect.
If you have negative weights, then the usual solution is to add the absolute value of the most negative weight to EVERY weight.
Why Bellman-Ford? Dijkstra should be sufficient for this problem. ( By default Dijkstra finds the cheapest path. You find the most expensive by assigning the absolute value of ( the original weight minus the greatest ) to every link. )

BellmanFord from text file not giving the same output as manual input

I am trying to read weights from a text file but it's not giving the same output as to when I am setting them manually.
This is the data present in the adjlist.txt file:
5
8
4
2
3
9
7
2
6
7
Now when I manually set these without the reading mechanism,
e.g:
graph->edge[0].weight = 5 and so on
it gives me this output
Vertex Distance from Source
0 0
1 6
2 10
3 7
4 10
I have tried fetching the data by just printing it and it certainly is reading it correctly but isn't parsing it properly
"cout << s[0] << "\n";"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include<bits/stdc++.h>
#include<fstream>
#include<string>
using namespace std;
// a structure to represent a weighted edge in graph
struct Edge
{
int src, dest, weight;
};
// a structure to represent a connected, directed and weighted graph
struct Graph
{
// V-> Number of vertices, E-> Number of edges
int V, E;
// graph is represented as an array of edges.
struct Edge* edge;
};
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
graph->V = V;
graph->E = E;
graph->edge = (struct Edge*) malloc(graph->E * sizeof(struct Edge));
return graph;
}
// A utility function used to print the solution
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
void relax(struct Graph* graph, int V, int dist[], int E, int src)
{
for (int i = 1; i <= V - 1; i++)
{
for (int j = 0; j < E; j++)
{
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
}
void int_source(int V,int dist[],int E,int src)
{
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
}
void negweight(struct Graph* graph, int V, int dist[], int E, int src)
{
for (int i = 0; i < E; i++)
{
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
printf("Graph contains negative weight cycle");
}
}
// The main function that finds shortest distances from src to all other
// vertices using Bellman-Ford algorithm. The function also detects negative
// weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
int_source(V,dist,E,src);
relax(graph,V,dist,E,src);
negweight(graph,V,dist,E,src);
printArr(dist, V);
return;
}
int main()
{
int V = 5; // Number of vertices in graph
int E = 10; // Number of edges in graph
struct Graph* graph = createGraph(V, E);
string s;
cout << "Your input file contains this adjacency list\n";
ifstream infile("adjlist.txt");
while(getline(infile,s))
{
graph->edge[0].src = 1;
graph->edge[0].dest = 2;
graph->edge[0].weight = s[0]-'0';
// add edge 0-2 (or A-C in above figure)
graph->edge[1].src = 1;
graph->edge[1].dest = 3;
graph->edge[1].weight = s[0]-'0';
// add edge 1-2 (or B-C in above figure)
graph->edge[2].src = 1;
graph->edge[2].dest = 4;
graph->edge[2].weight = s[0]-'0';
// add edge 1-3 (or B-D in above figure)
graph->edge[3].src = 2;
graph->edge[3].dest = 1;
graph->edge[3].weight = s[0]-'0';
// add edge 1-4 (or A-E in above figure)
graph->edge[4].src = 3;
graph->edge[4].dest = 2;
graph->edge[4].weight = s[0]-'0';
// add edge 3-2 (or D-C in above figure)
graph->edge[5].src = 3;
graph->edge[5].dest = 4;
graph->edge[5].weight = s[0]-'0';
// add edge 3-1 (or D-B in above figure)
graph->edge[6].src = 4;
graph->edge[6].dest = 2;
graph->edge[6].weight = s[0]-'0';
// add edge 4-3 (or E-D in above figure)
graph->edge[7].src = 4;
graph->edge[7].dest = 0;
graph->edge[7].weight = s[0]-'0';
// add edge 4-3 (or E-D in above figure)
graph->edge[8].src = 0;
graph->edge[8].dest = 1;
graph->edge[8].weight = s[0]-'0'; // add edge 4-3 (or E-D in above figure)
graph->edge[9].src = 0;
graph->edge[9].dest = 3;
graph->edge[9].weight = s[0]-'0';
}
BellmanFord(graph, 0);
return 0;
} `
Expected result should be
Vertex Distance from Source
0 0
1 6
2 10
3 7
4 10
Result I am getting is
Vertex Distance from Source
0 0
1 7
2 14
3 7
4 14
Take a closer look at the main parsing loop. For each line read from the file it sets the same value in the weight for all of the nodes.
Example:
graph->edge[0].src = 1;
graph->edge[0].dest = 2;
graph->edge[0].weight = s[0]-'0'; // 5
// add edge 0-2 (or A-C in above figure)
graph->edge[1].src = 1;
graph->edge[1].dest = 3;
graph->edge[1].weight = s[0]-'0'; // still five.
What you want is
int index = 0;
while(getline(infile,s))
{
graph->edge[index].src = 1;
graph->edge[index].dest = 2;
graph->edge[index].weight = s[0]-'0';
index++
}
Unfortunately this doesn't seem to fix everything. I can't see a way to enter the body of
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
with the given inputs.
So the answer to the question was with the help of #user4581301
I changed my input file so the source and destination would be added in the file as well.
now the loop runs fine
1,2,5
1,3,8
1,4,4
2,1,2
3,2,3
3,4,9
4,2,7
4,0,2
0,1,6
0,3,7
this is the edit that i made
int index = 0;
while(getline(infile,s))
{
graph->edge[index].src = s[0]-'0';
graph->edge[index].dest = s[2]-'0';
graph->edge[index].weight = s[4]-'0';
index++;
}

Reduce a Multigraph with edge weights to simple graph with minimal edge weight

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.

Building MaxHeap Largest Not Being Sent To Top

I am trying to build a max heap out of a vector of size 10. It contains numbers 1-10. Yet my program will not set the largest value 10 to the largest variable because when comparing it exceeds my vector's range.
if ((l <= v.size()) && (v.at(l) > v.at(i)))
{largest = l;}
else { largest = i; }
if ((r <= v.size()) && (v.at(r) > v.at(largest))) // r at some point is 10. which exceeds v.
{largest = r;}
I tried setting an if statement around the code above that would catch the error, but then i get this:
INPUT: 1 2 3 4 5 6 7 8 9 10
OUTPUT: 9 8 7 4 5 6 3 2 1 10
Which is almost correct, but the 10 should be first. What can I do to make sure the heap builds correctly? Here is my full code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
vector<string> readFile(string fileName) { /* read in file. Works Fine.*/}
void display(vector<string>& v) {/*displays vector. works fine. */ }
inline int parent(int i){return i / 2; }
inline int left(int i) {return 2*i;}
inline int right(int i) {return 2*i + 1;}
void Max_Heapify(vector<string>& v, int i)
{
int largest;
int l = left(i);
int r = right(i);
i--;
if ((l <= v.size()) && (v.at(l) > v.at(i)))
{largest = l;}
else { largest = i; }
if ((r <= v.size()) && (v.at(r) > v.at(largest)))
{
largest = r;
}
if (largest != i)
{
string temp = v.at(i);
v.at(i) = v.at(largest);
v.at(largest) = temp;
Max_Heapify(v, largest);
}
}
void Build_Max_Heap(vector<string>& v, int length)
{
for (int i = (length / 2); i > 0; i--)
{
Max_Heapify(v, i);
}
}
int main() {
vector<string> vectorReadIn;
vector<string> sortedVector;
int x = 0;
string fileName = "C:/Users/user/Downloads/Algorithims/Perm Words/perm15k.txt";
vectorReadIn = readFile(fileName);
cout << "Unsorted file:" << endl;
display(vectorReadIn);
vectorReadIn.resize(vectorReadIn.size());
Build_Max_Heap(vectorReadIn, vectorReadIn.size());
display(vectorReadIn);
}
In addition to the comment by Igor Tandetnik, your calculations for left and right child are wrong. In a vector with index 0 being the first item, the root of your heap is at index 0. So the calculations for left and right child are:
left child: (2*x) + 1
right child: (2*x) + 2
The calculations you have are for a heap with the root at index 1.
Also, the loop in your Build_Max_Heap function needs to be:
for (int i = (length / 2); i >= 0; i--)
That is, you must check to see if the first item in the vector needs to be rearranged.

Ising Model in C++

I'm writing a code in C++ for a 2D Ising model. Here's what the code should do:
Generate random NxN lattice, with each site either +1 or -1 value.
Select a site at random
If site when flipped (+1 to -1 or -1 to +1) is a state of lower energy, flip state ie. if dE < 0, flip state. If flipped state is of higher energy, flip with acceptance rate w = e^{-b(dE)}. Where dE is the change in energy if state is flipped.
4.Do this for all NxN sites, without repetition. This is considered one sweep.
Do like 100 sweeps.
I'm having trouble with steps 1, 2 and 3, would appreciate any help! For step 1, I managed to create and display a lattice, but I can't seem to extract the value of a site at location (x, y). Steps 2 and 3, how do I use a boolean expression of some sort to flip according to acceptance probability?
#include <cstdlib>
#include <ctime>
using namespace std;
#include <iostream>
int main() //random generation of spin configuration
{
int L; //Total number of spins L = NxN
int N = 30 //A square lattice of length 30
double B=1; //magnetic field
double M; //Total Magnetization = Sum Si
double E; //Total Energy
int T = 1.0;
int nsweeps = 100; //number of sweeps
int de; //change in energy when flipped
double Boltzmann; //Boltzmann factor
int x,y; //randomly chosen lattice site
int i,j,a,c; //counters
int ROWS = 5;
int COLS = 5;
int matrix[ROWS][COLS];
srand ( static_cast<unsigned> ( time ( 0 ) ) );
for ( int i = 0; i < ROWS; i++ )
{
for ( int j = 0; j < COLS; j++ )
{
matrix[i][j] = rand () % 2 *2-1;
}
}
// showing the matrix on the screen
for(int i=0;i<ROWS;i++) // loop 3 times for three lines
{
for(int j=0;j<COLS;j++) // loop for the three elements on the line
{
cout<<matrix[i][j]; // display the current element out of the array
}
cout<<endl; // when the inner loop is done, go to a new line
}
return 0; // return 0 to the OS.
//boundary conditions and range
if(x<0) x += N;
if(x>=L) x -= N;
if(y<0) y += N;
if(y>=L) y -= N;
//counting total energy of configuration
{ int neighbour = 0; // nearest neighbour count
for(int i=0; i<L; i++)
for(int j=0; j<L; j++)
{ if(spin(i,j)==spin(i+1, j)) // count from each spin to the right and above
neighbour++;
else
neighbour--;
if(spin(i, j)==spin(i, j+1))
neighbour++;
else
neighbour--;
}
E = -J*neighbour - B*M;
//flipping spin
int x = int(srand48()*L); //retrieves spin from randomly choosen site
int y = int(srand48()*L);
int delta_M = -2*spin(x, y); //calculate change in Magnetization M
int delta_neighbour = spin(spinx-1, y) + spin(x+1, y)+ spin(x, y-1) + spin(x, y+1);
int delta_neighbour = -2*spin(x,y)* int delta_neighbour;
double delta_E = -J*delta_neighbour -B*delta_M;
//flip or not
if (delta_E<=0)
{ (x, y) *= -1; // flip spin and update values
M += delta_M;
E += delta_E;
}
}
To follow up on my comment:
There are too many issues with your code for a single answer. Try to
build your program step by step. Use functions which perform one
thing, and this they do well. Test each function individually and if
necessary try to find out why it does not work. Then post specific
questions again.
To get you started:
Store your lattice as a std::vector<int> lattice(N*N)
Access element (x,y) with data[x+N*y].
Example:
#include <vector>
struct IsingModel
{
unsigned size_;
std::vector<int> lattice_;
// access element (x,y)
int& at(int x, int y) {
return lattice_[x + y*size_];
}
int at(int x, int y) const {
return lattice_[x + y*size_];
}
// generate size x size lattice
IsingModel(unsigned size)
: size_(size), lattice_(size*size, +1) {
}
static int BoolToSpin(bool v) {
return v ? +1 : -1;
}
// initialize spin randomly
void initializeRandom() {
for(int y=0; y<size_; y++) {
for(int x=0; x<size_; x++) {
at(x,y) = BoolToSpin(rand()%2);
}
}
}
static int Energy(int a, int b) {
return (a == b) ? +1 : -1;
}
// compute total energy
unsigned computeTotalEnergy() const {
unsigned energy = 0;
for(int y=1; y<size_-1; y++) {
for(int x=1; x<size_-1; x++) {
energy += Energy(at(x,y), at(x+1,y));
energy += Energy(at(x,y), at(x,y+1));
}
}
return energy ;
}
};
#include <iostream>
#include <cstdlib>
#include <ctime>
int main() {
srand(static_cast<unsigned>(time(0))); // intialize random number generator
IsingModel im(10);
im.initializeRandom();
unsigned energy = im.computeTotalEnergy();
std::cout << energy << std::endl; // print energy
}