C++ implementation of knapsack branch and bound - c++

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**

Related

Reason for Segmentation Fault During Depth First Search on Tree of Large Size C++

I'm trying to solve https://open.kattis.com/problems/rootedsubtrees and part of the solution requires finding the minimum distance between any 2 nodes on the tree. To do this, I'm using Lowest Common Ancestor as a subroutine. Part of my LCA code uses a DFS to traverse the tree. Somehow, running this code on a line graph of size 200000 leads to a segmentation fault during the DFS section of the code.
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
#define fast_cin() \
ios_base::sync_with_stdio(false); \
cin.tie(NULL); \
cout.tie(NULL);
int n, q, idx;
vector<int> adjlist[200009];
vector<int> L, E,
H; // depth at traversal index, node at traversal index, first traversal index of node
void dfs(int cur, int depth) {
cout << "dfs " << cur << " " << idx << endl;
H[cur] = idx;
E[idx] = cur;
L[idx++] = depth;
for (int &nxt : adjlist[cur]) {
if (H[nxt] != -1) continue;
dfs(nxt, depth + 1);
E[idx] = cur; // backtrack to current node
L[idx++] = depth;
}
}
class SparseTable { // OOP style
private:
vi A, P2, L2;
vector<vi> SpT; // the Sparse Table
public:
SparseTable() {} // default constructor
SparseTable(vi &initialA) { // pre-processing routine
A = initialA;
int n = (int)A.size();
int L2_n = (int)log2(n) + 1;
P2.assign(L2_n, 0);
L2.assign(1 << L2_n, 0);
for (int i = 0; i <= L2_n; ++i) {
P2[i] = (1 << i); // to speed up 2^i
L2[(1 << i)] = i; // to speed up log_2(i)
}
for (int i = 2; i < P2[L2_n]; ++i)
if (L2[i] == 0) L2[i] = L2[i - 1]; // to fill in the blanks
// the initialization phase
SpT = vector<vi>(L2[n] + 1, vi(n));
for (int j = 0; j < n; ++j) SpT[0][j] = j; // RMQ of sub array [j..j]
// the two nested loops below have overall time complexity = O(n log n)
for (int i = 1; P2[i] <= n; ++i) // for all i s.t. 2^i <= n
for (int j = 0; j + P2[i] - 1 < n; ++j) { // for all valid j
int x = SpT[i - 1][j]; // [j..j+2^(i-1)-1]
int y = SpT[i - 1][j + P2[i - 1]]; // [j+2^(i-1)..j+2^i-1]
SpT[i][j] = A[x] <= A[y] ? x : y;
}
}
int RMQ(int i, int j) {
int k = L2[j - i + 1]; // 2^k <= (j-i+1)
int x = SpT[k][i]; // covers [i..i+2^k-1]
int y = SpT[k][j - P2[k] + 1]; // covers [j-2^k+1..j]
return A[x] <= A[y] ? x : y;
}
};
int LCA(int u, int v, SparseTable &SpT) {
if (H[u] > H[v]) swap(u, v);
return E[SpT.RMQ(H[u], H[v])];
}
int APSP(int u, int v, SparseTable &SpT) {
int ancestor = LCA(u, v, SpT);
return L[H[u]] + L[H[v]] - 2 * L[H[ancestor]];
}
int main() {
fast_cin();
cin >> n >> q;
L.assign(2 * (n + 9), 0);
E.assign(2 * (n + 9), 0);
H.assign(n + 9, -1);
idx = 0;
int u, v;
for (int i = 0; i < n - 1; i++) {
cin >> u >> v;
u--;
v--;
adjlist[u].emplace_back(v);
adjlist[v].emplace_back(u);
}
dfs(0, 0);
SparseTable SpT(L);
ll d;
while (q--) {
cin >> u >> v;
u--;
v--;
d = (ll) APSP(u, v, SpT) + 1;
cout << (ll) n - d + (d) * (d + 1) / 2 << endl;
}
return 0;
}
Using the following Python Code to generate the input of a large line graph
n = 200000
q = 1
print(n, q)
for i in range(1, n):
print(i, i+1)
print(1, 200000)
I get the following last few lines of output before my program crashes.
.
.
.
dfs 174494 174494
dfs 174495 174495
dfs 174496 174496
dfs 174497 174497
dfs 174498 174498
Segmentation fault (core dumped)
Is the problem an issue of exhausting stack space with the recursion or something else?
You posted a lot of code, but here is one obvious error in the SparseMatrix class:
std::vector<int> P2;
//...
P2.assign(L2_n, 0);
for (int i = 0; i <= L2_n; ++i)
{
P2[i] = (1 << i); // <-- Out of bounds access when i == L2_n
To show you the error, change that line of code to this:
P2.at(i) = (1 << i); // <-- Out of bounds access when i == L2_n
You will now get a std::out_of_range exception thrown.
If you write a loop using <=, that loop will be considered suspicious, since a lot of off-by-one and buffer overrun errors occur with loop conditions written this way.
I believe stack exhaustion was the main problem in running the code on my machine. I re-implemented the DFS in an iterative fashion.
stack<tuple<int, int, bool>> st; // cur, depth, first_time
st.push ({0, 0, 1});
while (!st.empty()) {
auto [cur, depth, first_time] = st.top();
st.pop();
if (first_time){
H[cur] = idx;
}
E[idx] = cur;
L[idx++] = depth;
for (int &nxt : adjlist[cur]) {
if (H[nxt] != -1) continue;
st.push({cur, depth, 0});
st.push({nxt, depth+1, 1});
break;
}
}
and my code was able to run the large testcase on my machine.
I'm not sure is this is relevant to the original question, but after this change, the code still flagged a run-time error on the online judge and I eventually realized that the issue was that the sparse table was using too much memory, so I fixed that by avoiding wasted declared but not used memory spaces in rows of the sparse table. Then the online judge deemed it as being too slow. So I reverted the DFS code back to the recursive version, and it was accepted. Note that the accepted solution actually crashes on my machine when running the large testcase... I guess my machine has a more limited stack space than the online grader.
The accepted solution is here
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
#define fast_cin() \
ios_base::sync_with_stdio(false); \
cin.tie(NULL); \
cout.tie(NULL);
int n, q, idx;
vector<int> adjlist[(int)2e5 + 9];
vector<int> L, E,
H; // depth at traversal index, node at traversal index, first traversal index of node
void dfs(int cur, int depth) {
H[cur] = idx;
E[idx] = cur;
L[idx++] = depth;
for (int &nxt : adjlist[cur]) {
if (H[nxt] != -1) continue;
dfs(nxt, depth + 1);
E[idx] = cur; // backtrack to current node
L[idx++] = depth;
}
}
class SparseTable { // OOP style
private:
vi A, P2, L2;
vector<vi> SpT; // the Sparse Table
public:
SparseTable() {} // default constructor
SparseTable(vi &initialA) { // pre-processing routine
A = initialA;
int n = (int)A.size();
int L2_n = (int)log2(n) + 1;
P2.assign(L2_n + 1, 0);
L2.assign((1 << L2_n) + 1, 0);
for (int i = 0; i <= L2_n; ++i) {
P2[i] = (1 << i); // to speed up 2^i
L2[(1 << i)] = i; // to speed up log_2(i)
}
for (int i = 2; i < P2[L2_n]; ++i)
if (L2[i] == 0) L2[i] = L2[i - 1]; // to fill in the blanks
// the initialization phase
SpT = vector<vi>(L2[n] + 1, vi());
SpT[0] = vi(n, 0);
for (int j = 0; j < n; ++j) SpT[0][j] = j; // RMQ of sub array [j..j]
// the two nested loops below have overall time complexity = O(n log n)
for (int i = 1; P2[i] <= n; ++i) { // for all i s.t. 2^i <= n
SpT[i] = vi(n + 1 - P2[i]); // initialize SpT[i]
for (int j = 0; j + P2[i] - 1 < n; ++j) { // for all valid j
int x = SpT[i - 1][j]; // [j..j+2^(i-1)-1]
int y = SpT[i - 1][j + P2[i - 1]]; // [j+2^(i-1)..j+2^i-1]
SpT[i][j] = A[x] <= A[y] ? x : y;
}
}
}
int RMQ(int i, int j) {
int k = L2[j - i + 1]; // 2^k <= (j-i+1)
int x = SpT[k][i]; // covers [i..i+2^k-1]
int y = SpT[k][j - P2[k] + 1]; // covers [j-2^k+1..j]
return A[x] <= A[y] ? x : y;
}
};
int LCA(int u, int v, SparseTable &SpT) {
if (H[u] > H[v]) swap(u, v);
return E[SpT.RMQ(H[u], H[v])];
}
int APSP(int u, int v, SparseTable &SpT) {
int ancestor = LCA(u, v, SpT);
return L[H[u]] + L[H[v]] - 2 * L[H[ancestor]];
}
int main() {
fast_cin();
cin >> n >> q;
L.assign(2 * (n), 0);
E.assign(2 * (n), 0);
H.assign(n, -1);
idx = 0;
int u, v;
for (int i = 0; i < n - 1; i++) {
cin >> u >> v;
u--;
v--;
adjlist[u].emplace_back(v);
adjlist[v].emplace_back(u);
}
dfs(n - 1, 0);
SparseTable SpT(L);
ll d;
while (q--) {
cin >> u >> v;
u--;
v--;
d = (ll)APSP(u, v, SpT) + 1LL;
cout << (ll)n - d + (d) * (d + 1) / (ll)2 << endl;
}
return 0;
}

How to get the minimum XOR of a given value and the value from a query of range for a given array

Given an array A of n integers and given queries in the form of range [l , r] and a value x, find the minimum of A[i] XOR x where l <= i <= r and x will be different for different queries.
I tried solving this problem using segment trees but I am not sure what type of information I should store in them as x will be different for different queries.
0 < number of queries <= 1e4
0 < n <= 1e4
To solve this I used a std::vector as basis (not an array, or std::array), just for flexibility.
#include <algorithm>
#include <stdexcept>
#include <vector>
int get_xored_max(const std::vector<int>& values, const size_t l, const size_t r, const int xor_value)
{
// check bounds of l and r
if ((l >= values.size()) || (r >= values.size()))
{
throw std::invalid_argument("index out of bounds");
}
// todo check l < r
// create left & right iterators to create a smaller vector
// only containing the subset we're interested in.
auto left = values.begin() + l;
auto right = values.begin() + r + 1;
std::vector<int> range{ left, right };
// xor all the values in the subset
for (auto& v : range)
{
v ^= xor_value;
}
// use the standard library function for finding the iterator to the maximum
// then use the * to dereference the iterator and get the value
auto max_value = *std::max_element(range.begin(), range.end());
return max_value;
}
int main()
{
std::vector<int> values{ 1,3,5,4,2,4,7,9 };
auto max_value = get_xored_max(values, 0u, 7u, 3);
return 0;
}
Approach - Trie + Offline Processing
Time Complexity - O(N32)
Space Complexity - O(N32)
Edit:
This Approach will fail. I guess, we have to use square root decomposition instead of two pointers approach.
I have solved this problem using Trie for finding minimum xor in a range of [l,r]. I solved queries by offline processing by sorting them.
Input format:
the first line has n (no. of elements) and q (no. of queries). the second line has all n elements of the array. each subsequent line has a query and each query has 3 inputs l, r and x.
Example -
Input -
3 3
2 1 2
1 2 3
1 3 2
2 3 5
First, convert all 3 queries into queries sorted by l and r.
converted queries -
1 2 3
1 3 2
2 3 5
Key here is processing over sorted queries using two pointers approach.
#include <bits/stdc++.h>
using namespace std;
const int N = (int)2e4 + 77;
int n, q, l, r, x;
int a[N], ans[N];
vector<pair<pair<int, int>, pair<int, int>>> queries;
// Trie Implementation starts
struct node
{
int nxt[2], cnt;
void newnode()
{
memset(nxt, 0, sizeof(nxt));
cnt = 0;
}
} trie[N * 32];
int tot = 1;
void update(int x, int v)
{
int p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (!trie[p].nxt[id])
{
trie[++tot].newnode();
trie[p].nxt[id] = tot;
}
p = trie[p].nxt[id];
trie[p].cnt += v;
}
}
int minXor(int x)
{
int res = 0, p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (trie[p].nxt[id] and trie[trie[p].nxt[id]].cnt)
p = trie[p].nxt[id];
else
{
p = trie[p].nxt[id ^ 1];
res |= 1 << i;
}
}
return res;
}
// Trie Implementation ends
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; i += 1)
{
cin >> a[i];
}
for (int i = 1; i <= q; i += 1)
{
cin >> l >> r >> x;
queries.push_back({{l, r}, {x, i}});
}
sort(queries.begin(), queries.end());
int left = 1, right = 1;
for (int i = 0; i < q; i += 1)
{
int l = queries[i].first.first;
int r = queries[i].first.second;
int x = queries[i].second.first;
int index = queries[i].second.second;
while (left < l)
{
update(a[left], -1);
left += 1;
}
while (right <= r)
{
update(a[right], 1);
right += 1;
}
ans[index] = minXor(x);
}
for (int i = 1; i <= q; i += 1)
{
cout << ans[i] << " \n";
}
return 0;
}
Edit: with O(number of bits) code
Use a binary tree to store the values of A, look here : Minimum XOR for queries
What you need to change is adding to each node the range of indexes for A corresponding to the values in the leafs.
# minimal xor in a range
nbits=16 # Number of bits for numbers
asize=5000 # Array size
ntest=50 # Number of random test
from random import randrange
# Insert element a iindex iin the tree (increasing i only)
def tinsert(a,i,T):
for b in range(nbits-1,-1,-1):
v=((a>>b)&1)
T[v+2].append(i)
if T[v]==[]:T[v]=[[],[],[],[]]
T=T[v]
# Buildtree : builds a tree based on array V
def build(V):
T=[[],[],[],[]] # Init tree
for i,a in enumerate(V): tinsert(a,i,T)
return(T)
# Binary search : is T intersec [a,b] non empty ?
def binfind(T,a,b):
s,e,om=0,len(T)-1,-1
while True:
m=(s+e)>>1
v=T[m]
if v<a:
s=m
if m==om: return(a<=T[e]<=b)
elif v>b:
e=m
if m==om: return(a<=T[s]<=b)
else: return(True) # a<=T(m)<=b
om=m
# Look for the min xor in a give range index
def minx(x,s,e,T):
if s<0 or s>=(len(T[2])+len(T[3])) or e<s: return
r=0
for b in range(nbits-1,-1,-1):
v=((x>>b)&1)
if T[v+2]==[] or not binfind(T[v+2],s,e): # not nr with b set to v ?
v=1-v
T=T[v]
r=(r<<1)|v
return(r)
# Tests the code on random arrays
max=(1<<nbits)-1
for i in range(ntest):
A=[randrange(0,max) for i in range(asize)]
T=build(A)
x,s=randrange(0,max),randrange(0,asize-1)
e=randrange(s,asize)
if min(v^x for v in A[s:e+1])!=x^minx(x,s,e,T):
print('error')
I was able to solve this using segment tree and tries as suggested by #David Eisenstat
Below is an implementation in c++.
I constructed a trie for each segment in the segment tree. And finding the minimum xor is just traversing and matching the corresponding trie using each bit of the query value (here)
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i < b; i++)
using namespace std;
const int bits = 7;
struct trie {
trie *children[2];
bool end;
};
trie *getNode(void)
{
trie *node = new trie();
node->end = false;
node->children[0] = NULL;
node->children[1] = NULL;
return node;
}
trie *merge(trie *l, trie *r)
{
trie *node = getNode();
// Binary 0:
if (l->children[0] && r->children[0])
node->children[0] = merge(l->children[0], r->children[0]);
else if (!r->children[0])
node->children[0] = l->children[0];
else if (!l->children[0])
node->children[0] = r->children[0];
// Binary 1:
if (l->children[1] && r->children[1])
node->children[1] = merge(l->children[1], r->children[1]);
else if (!r->children[1])
node->children[1] = l->children[1];
else if (!l->children[1])
node->children[1] = r->children[1];
return node;
}
void insert(trie *root, int num)
{
int mask = 1 << bits;
int bin;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) root->children[bin] = getNode();
root = root->children[bin];
mask = mask >> 1;
}
root->end = true;
}
struct _segTree {
int n, height, size;
vector<trie *> tree;
_segTree(int _n)
{
n = _n;
height = (int)ceil(log2(n));
size = (int)(2 * pow(2, height) - 1);
tree.resize(size);
}
trie *construct(vector<int> A, int start, int end, int idx)
{
if (start == end) {
tree[idx] = getNode();
insert(tree[idx], A[start]);
return tree[idx];
}
int mid = start + (end - start) / 2;
tree[idx] = merge(construct(A, start, mid, 2 * idx + 1),
construct(A, mid + 1, end, 2 * idx + 2));
return tree[idx];
}
int findMin(int num, trie *root)
{
int mask = 1 << bits;
int bin;
int rnum = 0;
int res = 0;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) {
bin = 1 - bin;
if (!root->children[bin]) return res ^ num;
}
rnum |= (bin << (bits - i));
root = root->children[bin];
if (root->end) res = rnum;
mask = mask >> 1;
}
return res ^ num;
}
int Query(int X, int start, int end, int qstart, int qend, int idx)
{
if (qstart <= start && qend >= end) return findMin(X, tree[idx]);
if (qstart > end || qend < start) return INT_MAX;
int mid = start + (end - start) / 2;
return min(Query(X, start, mid, qstart, qend, 2 * idx + 1),
Query(X, mid + 1, end, qstart, qend, 2 * idx + 2));
}
};
int main()
{
int n, q;
vector<int> A;
vector<int> L;
vector<int> R;
vector<int> X;
cin >> n;
A.resize(n, 0);
rep(i, 0, n) cin >> A[i];
cin >> q;
L.resize(q);
R.resize(q);
X.resize(q);
rep(i, 0, q) cin >> L[i] >> R[i] >> X[i];
//---------------------code--------------------//
_segTree segTree(n);
segTree.construct(A, 0, n - 1, 0);
rep(i, 0, q)
{
cout << segTree.Query(X[i], 0, n - 1, L[i], R[i], 0) << " ";
}
return 0;
}
Time complexity : O((2n - 1)*k + qklogn)
Space complexity : O((2n - 1)*2k)
k -> number of bits

Find the sum of weights of edges between every pair of nodes in a weighted tree

I need to find an efficient way to find the sum of values of all simple paths in a weighted tree. The value of a simple path is defined as the sum of weights of all edges in the given simple path.
This is my try, but it is not working. Please tell the correct approach.
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int, ll> pil;
const int MAXN = 1e5;
int n, color[MAXN + 2];
vector<pil> adj[MAXN + 2];
ll sum1, cnt1[MAXN + 2], cnt[MAXN + 2], res;
void visit(int u, int p)
{
cnt[u] = 1;
cnt1[u] = color[u];
for (int i = 0; i < (int) adj[u].size(); ++i)
{
int v = adj[u][i].first;
ll w = adj[u][i].second;
if (v == p)
continue;
visit(v, u);
ll tmp = cnt1[v] * (n - sum1 - cnt[v] + cnt1[v]);
tmp += (cnt[v] - cnt1[v]) * (sum1 - cnt1[v]);
res += tmp * w;
cnt[u] += cnt[v];
cnt1[u] += cnt1[v];
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", color + i);
sum1 += color[i];
}
for (int i = 1, u, v; i < n; ++i)
{
scanf("%d %d %lld", &u, &v, &res);
adj[u].push_back(pil(v, res));
adj[v].push_back(pil(u, res));
}
res = 0;
visit(1, -1);
printf("%lld\n", res);
return 0;
}
Below is Simple implementation of what #Arjun Singh explained.
int64_t ans = 0;
int dfs(int node, int parent) {
int cur_subtree_size = 1;
for(int child : adj[node]) {
if(parent != child) {
int child_subtree_size = dfs(child, node);
int64_t contribution_of_cur_edge = child_subtree_size * (N - child_subtree_size) * weight[{node, child}];
ans += contribution_of_cur_edge;
cur_subtree_size += child_subtree_size;
}
}
return cur_subtree_size;
}
You can calculate the contribution of each edge in the final answer. Let's say an edge connects two components component1 ---- component2. Then the contribution of this edge in final answer will be -
Vertices(component1) * Vertices(component2)*edge_weight.
The no. of vertices in each component can be found easily running a dfs and calculating the number of vertices in the subtree of each vertex. Let an edge connect vertex u and v. u is the parent of v. Then,
Vertices(v) = Number of vertices in the subtree of v = Vertices(component1)
Vertices(component2) = n - Vertices(v)
You can precalculate this subtree array. So final time complexity will be O(n).

to detect path in bfs

i am doing a standard problem to calculate min moves to reach target by a knight but i also want to keep track of path but its showing error.it dispalys
prog.cpp: In function
'int minStepToReachTarget(int*, int*, int)':
prog.cpp:76:42: error: no match for 'operator[]' (operand types are
'std::vector<cell>' and 'cell')
{q.push(cell(x, y, t.dis + 1));parent[cell(x, y, t.dis + 1)]=t;}
I have commented down the line 76 in my code.
struct cell {
int x, y;
int dis;
cell() {}
cell(int x, int y, int dis): x(x), y(y), dis(dis) {}
};
//cell parent[10000];
typedef cell c;
vector<c> parent(10000);
bool isInside(int x, int y, int N) {
if (x >= 1 && x <= N && y >= 1 && y <= N)
return true;
return false;
}
int minStepToReachTarget(int knightPos[], int targetPos[], int N) {
// x and y direction, where a knight can move
int dx[] = {-2, -1, 1, 2, -2, -1, 1, 2};
int dy[] = {-1, -2, -2, -1, 1, 2, 2, 1};
// queue for storing states of knight in board
queue<cell> q;
// push starting position of knight with 0 distance
q.push(cell(knightPos[0], knightPos[1], 0));
cell t;
int x, y;
bool visit[N + 1][N + 1];
// make all cell unvisited
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
visit[i][j] = false;
visit[knightPos[0]][knightPos[1]] = true;
// parent[cell(knightPos[0], knightPos[1], 0)]=t;
// loop untill we have one element in queue
while (!q.empty()) {
t = q.front();
//parent[t]=t;
q.pop();
visit[t.x][t.y] = true;
// if current cell is equal to target cell,
// return its distance
if (t.x == targetPos[0] && t.y == targetPos[1])
return t.dis;
// loop for all reahable states
for (int i = 0; i < 8; i++) {
x = t.x + dx[i];
y = t.y + dy[i];
// If rechable state is not yet visited and
// inside board, push that state into queue
if (isInside(x, y, N) && !visit[x][y]) {
q.push(cell(x, y, t.dis + 1));
//76 ERROR: parent[cell(x, y, t.dis + 1)]=t;}
}
}
}
int main() {
// size of square board
int N = 6;
int knightPos[] = {4, 5};
int targetPos[] = {1, 1};
int m= minStepToReachTarget(knightPos, targetPos, N);
cout<<m<<endl;
return 0;
}
#Code
int dx[8] = {-1,-2, 1 ,2 ,-1, -2, 1, 2};
int dy[8] = {-2,-1, -2,-1, 2, 1, 2, 1};
q.push(ppi(pi(kx, ky), 0));
while(!q.empty()){
pi cur = q.front().first; int d = q.front().second; q.pop();
int x = cur.first;
int y = cur.second;
// printf("%d %d %d\n", x,y, visited[x][y]);
if(visited[x][y]) continue;
visited[x][y] = true;
if (x == tx && y == ty){
printf("%d", d);
return 0;
}
for(int i = 0; i<8; i++){
int nx = x+dx[i];
int ny = y+dy[i];
if(nx <= 0 || nx > n || ny <= 0 || ny > n) continue;
q.push(ppi(pi(nx, ny), d+1));
}
}
printf("-1");
Explanation
Here, this is the bfs which I implemented. I am storing the grid as a boolean value, I can keep track of which squares I have traveled too. If I am unable to reach the square, I output -1. I would also recommend not using function calls unless really necessary, as this is a simple BFS question.
Extension
Just in case you want to find out more, I took the following chunk from my code for a harder problem, where there exists a grid with forbidden squares where the knight cannot travel. In that case, forbidden squares are initially marked as 'true' instead of 'false' to signify that is traveled so I will not go on it.
I hope my above solution helps.

Divide and Conquer Algorithm for Finding the Maximum Subarray - How to also provide the result subarray indexes?

Excuse me, I have an assignment to solve the Maximum Sub Array Problem using the Brute Force Algorithm O(n^2), Divide and Conquer O(nlogn) and Kadane's Algorithm O(n). (My code is different).
"For example, for the sequence of values {−2, 1, −3, 4, −1, 2, 1, −5, 4}, the contiguous sub-array with the largest sum is [4, −1, 2, 1] with sum 6." - From the Wiki Page.
I am done with Kadane's and BruteForce, Where my required output is not just to find the sum, but also the starting index of the found sub-array and the ending index.
My current DivideAndConquer code gets me the correct sum. However, I can't see a way to keep track of my indexes since I implemented it recursively (of course). And I don't know if the only way is to use global variables in this case (I prefer not).. Can you help solve that? Or will I need to change the whole design?
#include <iostream>
int DivideAndConquer(int[], int);
int main()
{
// Example 1
//const int MyArraySize = 16;
//int MyArray[MyArraySize] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 }; // answer: Index 7 -> 10, sum = 43
// Example 2
const int MyArraySize = 8;
int MyArray[MyArraySize] = { -2, -5, 6, -2, -3, 1, 5, -6 }; // answer: Index 2 -> 6, sum = 7
int FinalResult;
FinalResult = DivideAndConquer(MyArray, MyArraySize);
std::cout << "Using Divide And Conquer: With O(nlogn) Sum = " << FinalResult << "\n\n";
system("pause");
return 0;
}
int DivideAndConquer(int* _myArray, int _myArraySize)
{
if (_myArraySize == 1)
return _myArray[0];
int middle = _myArraySize / 2;
int Result_LeftPortion = DivideAndConquer(_myArray, middle);
int Result_RightPortion = DivideAndConquer(_myArray + middle, _myArraySize - middle);
int LeftSum = -9999;
int RightSum = -9999;
int TotalSum = 0;
for (int i = middle; i < _myArraySize; i++)
{
TotalSum += _myArray[i];
RightSum = TotalSum < RightSum ? RightSum : TotalSum;
}
TotalSum = 0;
for (int i = middle - 1; i >= 0; i--)
{
TotalSum += _myArray[i];
LeftSum = TotalSum < LeftSum ? LeftSum : TotalSum;
}
int PartialResult = LeftSum < RightSum ? RightSum : LeftSum;
int Result= (PartialResult < LeftSum + RightSum ? LeftSum + RightSum : PartialResult);
return Result;
}
Your algorithm has logical problems and it is not optimal. You are not even using the Result_LeftPortion, Result_RightPortion values. Your final result is always maximum of RightSum, LeftSum and TotalSum of the whole array. The values from all other subarrays gets ignored.
One way solve to solve this problem with divide and conquer is as follows. You should save four values for each subarray:
Maximum sum that contains the left element ( s_l )
Maximum sum that contains the right element ( s_r )
Sum of the whole array ( t )
Maximum of above values ( mx )
For the case that you are checking a subarray of size 1 all of these values are equal to the value of that element.
When merging two subarrays (sub_left, sub_right) these values will be:
s_l = max( sub_left.s_l, sub_left.t + sub_right.s_l )
s_r = max( sub_right.s_r, sub_right.t + sub_left.s_r )
t = sum( sub_left.t + sub_right.t )
mx = max( s_l, s_r, t, sub_right.mx, sub_left.mx, sub_left.r+sub_right.l)
The final result will be the value of mx of the array.
For finding the position of the subarray with maximum sum you should keep a right index and left index for each of these values and update them accordingly when you perform merge. Consider this case
sub_left.s_r range is (2,5)
sub_right.t range is (6,10)
if ( sub_right.t + sub_left.s_r > sub_right.s_r )
s_r range = (2,10)
This is my implementation:
#include <iostream>
using namespace std;
struct node {
//value, right index, left index
int value, r, l;
node(int _v, int _r, int _l){
value = _v;
r = _r;
l = _l;
}
node (){}
};
struct sub {
// max node containing left element
// max node containing right element
// total node
// max node
node s_l, s_r, t, mx;
sub ( node _l, node _r, node _t, node _mx ){
s_l = _l;
s_r = _r;
t = _t;
mx = _mx;
}
sub(){}
};
sub DivideAndConquer(int* _myArray, int left, int right)
{
if(right == left){
node n (_myArray[left],right,left);
return sub( n, n, n, n);
}
int mid = (left+right)/2;
sub sub_left = DivideAndConquer( _myArray, left, mid);
sub sub_right = DivideAndConquer( _myArray, mid+1, right);
sub cur;
if ( sub_left.t.value + sub_right.s_l.value > sub_left.s_l.value ){
cur.s_l.value = sub_left.t.value + sub_right.s_l.value;
cur.s_l.r = sub_right.s_l.r;
cur.s_l.l = sub_left.s_l.l;
} else {
cur.s_l = sub_left.s_l;
}
if ( sub_right.t.value + sub_left.s_r.value > sub_right.s_r.value ){
cur.s_r.value = sub_right.t.value + sub_left.s_r.value;
cur.s_r.l = sub_left.s_r.l;
cur.s_r.r = sub_right.s_r.r;
} else {
cur.s_r = sub_right.s_r;
}
cur.t.value = sub_right.t.value + sub_left.t.value;
cur.t.r = sub_right.t.r;
cur.t.l = sub_left.t.l;
if ( cur.s_r.value >= cur.s_l.value &&
cur.s_r.value >= cur.t.value &&
cur.s_r.value >= sub_left.mx.value &&
cur.s_r.value >= sub_right.mx.value ){
cur.mx = cur.s_r;
} else if ( cur.s_l.value >= cur.s_r.value &&
cur.s_l.value >= cur.t.value &&
cur.s_l.value >= sub_left.mx.value &&
cur.s_l.value >= sub_right.mx.value ){
cur.mx = cur.s_l;
} else if ( sub_left.mx.value >= cur.s_l.value &&
sub_left.mx.value >= cur.t.value &&
sub_left.mx.value >= cur.s_r.value &&
sub_left.mx.value >= sub_right.mx.value ){
cur.mx = sub_left.mx;
} else {
cur.mx = sub_right.mx;
}
if ( sub_left.s_r.value + sub_right.s_l.value > cur.mx.value ){
cur.mx.value = sub_left.s_r.value + sub_right.s_l.value;
cur.mx.l = sub_left.s_r.l;
cur.mx.r = sub_right.s_l.r;
}
return cur;
}
int main()
{
// Example 1
//const int MyArraySize = 16;
//int MyArray[MyArraySize] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 }; // answer: Index 7 -> 10, sum = 43
// Example 2
const int MyArraySize = 8;
int MyArray[MyArraySize] = { -2, -5, 6, -2, -3, 1, 5, -6 }; // answer: Index 2 -> 6, sum = 7
sub FinalResult = DivideAndConquer(MyArray, 0,MyArraySize-1);
std::cout << "Sum = " << FinalResult.mx.value << std::endl;
std::cout << "( " << FinalResult.mx.l << " , " << FinalResult.mx.r << ")" << std::endl;
// system("pause");
return 0;
}
NOTE: This algorithm runs in O(n) time.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MINUS_INFINITY -1e10
float Find_max_cross_subarray(int I[],float A[]){
float left_sum = MINUS_INFINITY;
float right_sum = MINUS_INFINITY;
float sum = 0;
int left_max,right_max,i;
for(i=I[2];i>=I[0];i--){
sum = sum + A[i];
if(sum > left_sum){
left_sum = sum;
left_max = i;
}
}
sum = 0;
for(i=I[2]+1;i<=I[1];i++){
sum = sum + A[i];
if(sum > right_sum){
right_sum = sum;
right_max = i;
}
}
I[0] = left_max;
I[1] = right_max;
sum = left_sum + right_sum;
return sum;
}
float Find_max_subarray(int I[],float A[]){
int sum,mid;
int left[2];
int right[2];
int cross[3];
float left_sum,right_sum,cross_sum;
if(I[0] == I[1]){
sum = A[I[0]];
}
else {
mid = floor((I[0]+I[1])/2);
left[0] = I[0];
left[1] = mid;
right[0] = mid + 1;
right[1] = I[1];
cross[0] = I[0];
cross[1] = I[1];
cross[2] = mid;
left_sum = Find_max_subarray(left,A);
right_sum = Find_max_subarray(right,A);
cross_sum = Find_max_cross_subarray(cross,A);
if((left_sum >= right_sum)&&(left_sum >= cross_sum)){
sum = left_sum;
I[0] = left[0];
I[1] = left[1];
}
else if((right_sum >= left_sum)&&(right_sum >= cross_sum)){
sum = right_sum;
I[0] = right[0];
I[1] = right[1];
}
else{
sum = cross_sum;
I[0] = cross[0];
I[1] = cross[1];
}
}
return sum;
}
int main(){
int n,i;
float max_sum;
int I[2];
float A[100] = {13, -3, -25, 20, -3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
n = sizeof(A)/sizeof(A[0]);
I[0] = 0;
I[1] = n-1;
max_sum = Find_max_subarray(I,A);
printf("Maximum sub array is A[%d ......%d] with sum %f",I[0],I[1],max_sum);
}