// C++ Program to solve Traveling Salesman Problem using Branch and Bound.
#include <bits/stdc++.h>
using namespace std;
// N is number of total nodes on the graph or the cities in the map
#define N 5
// Sentinal value for representing infinity
#define INF INT_MAX
// State Space Tree nodes
struct Node
{
// stores edges of state space tree
// helps in tracing path when answer is found
vector<pair<int, int> > path;
// stores the reduced matrix
int reducedMatrix[N][N];
// stores the lower bound
int cost;
//stores current city number
int vertex;
// stores number of cities visited so far
int level;
};
// Function to allocate a new node
// (i, j) corresponds to visiting city j from city i
Node* newNode(int parentMatrix[N][N],
vector<pair<int, int> > path,
int level, int i, int j)
{
Node* node = new Node;
// stores ancestors edges of state space tree
node->path = path;
// skip for root node
if(level != 0 )
// add current edge to path
node->path.push_back(make_pair(i, j));
// copy data from parent node to current node
memcpy(node->reducedMatrix, parentMatrix,
sizeof node->reducedMatrix);
// Change all entries of row i and column j to infinity
// skip for root node
for(int k = 0; level != 0 && k < N; k++)
// set outgoing edges for city i to infinity
node->reducedMatrix[i][k] = INF,
// set incoming edges to city j to infinity
node->reducedMatrix[k][j] = INF;
// Set (j, 0) to infinity
// here start node is 0
node->reducedMatrix[j][0] = INF;
// set number of cities visited so far
node->level = level;
// assign current city number
node->vertex = j;
// return node
return node;
}
// Function to reduce each row in such a way that
// there must be at least one zero in each row
int rowReduction(int reducedMatrix[N][N], int row[N])
{
// initialize row array to INF
fill_n(row, N, INF);
// row[i] contains minimum in row i
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
if( reducedMatrix[i][j] < row[i])
row[i] = reducedMatrix[i][j];
// reduce the minimum value from each element in each row.
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
if(reducedMatrix[i][j] != INF && row[i] != INF)
reducedMatrix[i][j] -= row[i];
}
// Function to reduce each column in such a way that
// there must be at least one zero in each column
int columnReduction(int reducedMatrix[N][N], int col[N])
{
// initialize col array to INF
fill_n(col, N, INF);
// col[j] contains minimum in col j
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
if(reducedMatrix[i][j] < col[j])
col[j] = reducedMatrix[i][j];
// reduce the minimum value from each element in each column
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
if(reducedMatrix[i][j] != INF && col[j] != INF)
reducedMatrix[i][j] -= col[j];
}
// Function to get the lower bound on
// on the path starting at current min node
int calculateCost(int reducedMatrix[N][N])
{
// initialize cost to 0
int cost = 0;
// Row Reduction
int row[N];
rowReduction(reducedMatrix, row);
// Column Reduction
int col[N];
columnReduction(reducedMatrix, col);
// the total expected cost
// is the sum of all reductions
for(int i = 0; i < N; i++)
cost += (row[i] != INT_MAX) ? row[i] : 0,
cost += (col[i] != INT_MAX) ? col[i] : 0;
return cost;
}
// print list of cities visited following least cost
void printPath(vector<pair<int, int> > list)
{
for(int i = 0; i < list.size(); i++)
cout << list[i].first + 1<< " -> " <<
list[i].second + 1<< endl;
}
// Comparison object to be used to order the heap
struct comp
{
bool operator()(const Node* lhs, const Node* rhs) const
{
return lhs->cost > rhs->cost;
}
};
// Function to solve Traveling Salesman Problem using Branch and Bound.
int solve(int costMatrix[N][N])
{
// Create a priority queue to store live nodes of
// search tree;
priority_queue<Node*, std::vector<Node*>, comp> pq;
vector<pair<int, int> > v;
// create a root node and calculate its cost
// The TSP starts from first city i.e. node 0
Node* root = newNode(costMatrix, v, 0, -1, 0);
// get the lower bound of the path starting at node 0
root->cost = calculateCost(root->reducedMatrix);
// Add root to list of live nodes;
pq.push(root);
// Finds a live node with least cost,
// add its children to list of live nodes and
// finally deletes it from the list.
while(!pq.empty())
{
// Find a live node with least estimated cost
Node* min = pq.top();
// The found node is deleted from the list of
// live nodes
pq.pop();
// i stores current city number
int i = min->vertex;
// if all cities are visited
if(min->level == N - 1)
{
// return to starting city
min->path.push_back(make_pair(i, 0));
// print list of cities visited;
printPath(min->path);
// return optimal cost
return min->cost;
}
// do for each child of min
// (i, j) forms an edge in space tree
for(int j = 0; j < N; j++)
{
if(min->reducedMatrix[i][j] != INF)
{
// create a child node and calculate its cost
Node* child = newNode(min->reducedMatrix, min->path,
min->level+1, i, j);
/* Cost of the child =
cost of parent node +
cost of the edge(i, j) +
lower bound of the path starting at node j
*/
child->cost = min->cost + min->reducedMatrix[i][j] +
calculateCost(child->reducedMatrix);
// Add child to list of live nodes
pq.push(child);
}
}
// free node as we have already stored edges (i, j) in vector
// So no need for parent node while printing solution.
free(min);
}
}
// Driver function to test above functions
int main()
{
// cost matrix for traveling salesman problem.
/*int costMatrix[N][N] =
{
{INF, 5, INF, 6, 5, 4},
{5, INF, 2, 4, 3, INF},
{INF, 2, INF, 1, INF, INF},
{6, 4, 1, INF, 7, INF},
{5, 3, INF, 7, INF, 3},
{4, INF, INF, INF, 3, INF}
};
*/
// cost 34
int costMatrix[N][N] =
{
{INF, 10, 8, 9, 7},
{10, INF, 10, 5, 6},
{8, 10, INF, 8, 9},
{9, 5, 8, INF, 6},
{7, 6, 9, 6, INF}
};
/*// cost 16
int costMatrix[N][N] =
{
{INF, 3, 1, 5, 8},
{3, INF, 6, 7, 9},
{1, 6, INF, 4, 2},
{5, 7, 4, INF, 3},
{8, 9, 2, 3, INF}
};*/
/*
// cost 8
int costMatrix[N][N] =
{
{INF, 2, 1, INF},
{2, INF, 4, 3},
{1, 4, INF, 2},
{INF, 3, 2, INF}
};
//cost 12
int costMatrix[N][N] =
{
{INF, 5, 4, 3},
{3, INF, 8, 2},
{5, 3, INF, 9},
{6, 4, 3, INF}
};
*/
cout << "\n\nTotal Cost is " << solve(costMatrix);
return 0;
}
Ly8gQysrIFByb2dyYW0gdG8gc29sdmUgVHJhdmVsaW5nIFNhbGVzbWFuIFByb2JsZW0gdXNpbmcgQnJhbmNoIGFuZCBCb3VuZC4KI2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgovLyBOIGlzIG51bWJlciBvZiB0b3RhbCBub2RlcyBvbiB0aGUgZ3JhcGggb3IgdGhlIGNpdGllcyBpbiB0aGUgbWFwCiNkZWZpbmUgTiA1Ci8vIFNlbnRpbmFsIHZhbHVlIGZvciByZXByZXNlbnRpbmcgaW5maW5pdHkKI2RlZmluZSBJTkYgSU5UX01BWAoKLy8gU3RhdGUgU3BhY2UgVHJlZSBub2RlcwpzdHJ1Y3QgTm9kZQp7CiAgICAvLyBzdG9yZXMgZWRnZXMgb2Ygc3RhdGUgc3BhY2UgdHJlZQogICAgLy8gaGVscHMgaW4gdHJhY2luZyBwYXRoIHdoZW4gYW5zd2VyIGlzIGZvdW5kCiAgICB2ZWN0b3I8cGFpcjxpbnQsIGludD4gPiBwYXRoOwoKICAgIC8vIHN0b3JlcyB0aGUgcmVkdWNlZCBtYXRyaXgKICAgIGludCByZWR1Y2VkTWF0cml4W05dW05dOwoKICAgIC8vIHN0b3JlcyB0aGUgbG93ZXIgYm91bmQgCiAgICBpbnQgY29zdDsKCgkvL3N0b3JlcyBjdXJyZW50IGNpdHkgbnVtYmVyCiAgICBpbnQgdmVydGV4OwoKCS8vIHN0b3JlcyBudW1iZXIgb2YgY2l0aWVzIHZpc2l0ZWQgc28gZmFyCiAgICBpbnQgbGV2ZWw7Cn07CgovLyBGdW5jdGlvbiB0byBhbGxvY2F0ZSBhIG5ldyBub2RlCi8vIChpLCBqKSBjb3JyZXNwb25kcyB0byB2aXNpdGluZyBjaXR5IGogZnJvbSBjaXR5IGkKTm9kZSogbmV3Tm9kZShpbnQgcGFyZW50TWF0cml4W05dW05dLCAKCQkJdmVjdG9yPHBhaXI8aW50LCBpbnQ+ID4gcGF0aCwgCgkJCWludCBsZXZlbCwgaW50IGksIGludCBqKQp7CiAgICBOb2RlKiBub2RlID0gbmV3IE5vZGU7CgoJLy8gc3RvcmVzIGFuY2VzdG9ycyBlZGdlcyBvZiBzdGF0ZSBzcGFjZSB0cmVlCiAgICBub2RlLT5wYXRoID0gcGF0aDsKCS8vIHNraXAgZm9yIHJvb3Qgbm9kZQogICAgaWYobGV2ZWwgIT0gMCApCgkJLy8gYWRkIGN1cnJlbnQgZWRnZSB0byBwYXRoCiAgICAgICAgbm9kZS0+cGF0aC5wdXNoX2JhY2sobWFrZV9wYWlyKGksIGopKTsKCiAgICAvLyBjb3B5IGRhdGEgZnJvbSBwYXJlbnQgbm9kZSB0byBjdXJyZW50IG5vZGUKICAgIG1lbWNweShub2RlLT5yZWR1Y2VkTWF0cml4LCBwYXJlbnRNYXRyaXgsIAogICAgCQlzaXplb2Ygbm9kZS0+cmVkdWNlZE1hdHJpeCk7CgoJLy8gQ2hhbmdlIGFsbCBlbnRyaWVzIG9mIHJvdyBpIGFuZCBjb2x1bW4gaiB0byBpbmZpbml0eQoJLy8gc2tpcCBmb3Igcm9vdCBub2RlCiAgICBmb3IoaW50IGsgPSAwOyBsZXZlbCAhPSAwICYmIGsgPCBOOyBrKyspCgkJLy8gc2V0IG91dGdvaW5nIGVkZ2VzIGZvciBjaXR5IGkgdG8gaW5maW5pdHkKICAgICAgICBub2RlLT5yZWR1Y2VkTWF0cml4W2ldW2tdID0gSU5GLAoJCS8vIHNldCBpbmNvbWluZyBlZGdlcyB0byBjaXR5IGogdG8gaW5maW5pdHkKICAgICAgICBub2RlLT5yZWR1Y2VkTWF0cml4W2tdW2pdID0gSU5GOwoKCS8vIFNldCAoaiwgMCkgdG8gaW5maW5pdHkgCgkvLyBoZXJlIHN0YXJ0IG5vZGUgaXMgMAogICAgbm9kZS0+cmVkdWNlZE1hdHJpeFtqXVswXSA9IElORjsKCiAgICAvLyBzZXQgbnVtYmVyIG9mIGNpdGllcyB2aXNpdGVkIHNvIGZhcgogICAgbm9kZS0+bGV2ZWwgPSBsZXZlbDsKCQoJLy8gYXNzaWduIGN1cnJlbnQgY2l0eSBudW1iZXIKICAgIG5vZGUtPnZlcnRleCA9IGo7CgoJLy8gcmV0dXJuIG5vZGUKICAgIHJldHVybiBub2RlOwp9CgovLyBGdW5jdGlvbiB0byByZWR1Y2UgZWFjaCByb3cgaW4gc3VjaCBhIHdheSB0aGF0IAovLyB0aGVyZSBtdXN0IGJlIGF0IGxlYXN0IG9uZSB6ZXJvIGluIGVhY2ggcm93CmludCByb3dSZWR1Y3Rpb24oaW50IHJlZHVjZWRNYXRyaXhbTl1bTl0sIGludCByb3dbTl0pCnsKCS8vIGluaXRpYWxpemUgcm93IGFycmF5IHRvIElORiAKICAgIGZpbGxfbihyb3csIE4sIElORik7CgkKCS8vIHJvd1tpXSBjb250YWlucyBtaW5pbXVtIGluIHJvdyBpCiAgICBmb3IoaW50IGkgPSAwOyBpIDwgTjsgaSsrKQogICAgICAgIGZvcihpbnQgaiA9IDA7IGogPCBOOyBqKyspCiAgICAgICAgICAgIGlmKCByZWR1Y2VkTWF0cml4W2ldW2pdIDwgcm93W2ldKQogICAgICAgICAgICAgICAgcm93W2ldID0gcmVkdWNlZE1hdHJpeFtpXVtqXTsKCgkvLyByZWR1Y2UgdGhlIG1pbmltdW0gdmFsdWUgZnJvbSBlYWNoIGVsZW1lbnQgaW4gZWFjaCByb3cuCiAgICBmb3IoaW50IGkgPSAwOyBpIDwgTjsgaSsrKQogICAgICAgIGZvcihpbnQgaiA9IDA7IGogPCBOOyBqKyspCiAgICAgICAgICAgIGlmKHJlZHVjZWRNYXRyaXhbaV1bal0gIT0gSU5GICYmIHJvd1tpXSAhPSBJTkYpCiAgICAgICAgICAgICAgICByZWR1Y2VkTWF0cml4W2ldW2pdIC09IHJvd1tpXTsKfQoKCi8vIEZ1bmN0aW9uIHRvIHJlZHVjZSBlYWNoIGNvbHVtbiBpbiBzdWNoIGEgd2F5IHRoYXQKLy8gdGhlcmUgbXVzdCBiZSBhdCBsZWFzdCBvbmUgemVybyBpbiBlYWNoIGNvbHVtbgppbnQgY29sdW1uUmVkdWN0aW9uKGludCByZWR1Y2VkTWF0cml4W05dW05dLCBpbnQgY29sW05dKQp7CgkvLyBpbml0aWFsaXplIGNvbCBhcnJheSB0byBJTkYgCiAgICBmaWxsX24oY29sLCBOLCBJTkYpOwoKCS8vIGNvbFtqXSBjb250YWlucyBtaW5pbXVtIGluIGNvbCBqCiAgICBmb3IoaW50IGkgPSAwOyBpIDwgTjsgaSsrKQogICAgICAgIGZvcihpbnQgaiA9IDA7IGogPCBOOyBqKyspCiAgICAgICAgICAgIGlmKHJlZHVjZWRNYXRyaXhbaV1bal0gPCBjb2xbal0pCiAgICAgICAgICAgICAgICBjb2xbal0gPSByZWR1Y2VkTWF0cml4W2ldW2pdOwoKCS8vIHJlZHVjZSB0aGUgbWluaW11bSB2YWx1ZSBmcm9tIGVhY2ggZWxlbWVudCBpbiBlYWNoIGNvbHVtbgogICAgZm9yKGludCBpID0gMDsgaSA8IE47IGkrKykKICAgICAgICBmb3IoaW50IGogPSAwOyBqIDwgTjsgaisrKQogICAgICAgICAgICBpZihyZWR1Y2VkTWF0cml4W2ldW2pdICE9IElORiAmJiBjb2xbal0gIT0gSU5GKQogICAgICAgICAgICAgICAgcmVkdWNlZE1hdHJpeFtpXVtqXSAtPSBjb2xbal07CQp9CgovLyBGdW5jdGlvbiB0byBnZXQgdGhlIGxvd2VyIGJvdW5kIG9uCi8vIG9uIHRoZSBwYXRoIHN0YXJ0aW5nIGF0IGN1cnJlbnQgbWluIG5vZGUKaW50IGNhbGN1bGF0ZUNvc3QoaW50IHJlZHVjZWRNYXRyaXhbTl1bTl0pCnsKCS8vIGluaXRpYWxpemUgY29zdCB0byAwCiAgICBpbnQgY29zdCA9IDA7CgkKCS8vIFJvdyBSZWR1Y3Rpb24KICAgIGludCByb3dbTl07Cglyb3dSZWR1Y3Rpb24ocmVkdWNlZE1hdHJpeCwgcm93KTsKCQoJLy8gQ29sdW1uIFJlZHVjdGlvbgogICAgaW50IGNvbFtOXTsKICAgIGNvbHVtblJlZHVjdGlvbihyZWR1Y2VkTWF0cml4LCBjb2wpOwoKCS8vIHRoZSB0b3RhbCBleHBlY3RlZCBjb3N0IAoJLy8gaXMgdGhlIHN1bSBvZiBhbGwgcmVkdWN0aW9ucwogICAgZm9yKGludCBpID0gMDsgaSA8IE47IGkrKykKICAgICAgICBjb3N0ICs9IChyb3dbaV0gIT0gSU5UX01BWCkgPyByb3dbaV0gOiAwLAogICAgICAgIGNvc3QgKz0gKGNvbFtpXSAhPSBJTlRfTUFYKSA/IGNvbFtpXSA6IDA7CgogICAgcmV0dXJuIGNvc3Q7Cn0KCi8vIHByaW50IGxpc3Qgb2YgY2l0aWVzIHZpc2l0ZWQgZm9sbG93aW5nIGxlYXN0IGNvc3QKdm9pZCBwcmludFBhdGgodmVjdG9yPHBhaXI8aW50LCBpbnQ+ID4gbGlzdCkKewogICAgZm9yKGludCBpID0gMDsgaSA8IGxpc3Quc2l6ZSgpOyBpKyspCiAgICAgICAgY291dCA8PCBsaXN0W2ldLmZpcnN0ICsgMTw8ICIgLT4gIiA8PAogICAgICAgICAgICAgICAgbGlzdFtpXS5zZWNvbmQgKyAxPDwgZW5kbDsKfQoKLy8gQ29tcGFyaXNvbiBvYmplY3QgdG8gYmUgdXNlZCB0byBvcmRlciB0aGUgaGVhcApzdHJ1Y3QgY29tcAp7CiAgICBib29sIG9wZXJhdG9yKCkoY29uc3QgTm9kZSogbGhzLCBjb25zdCBOb2RlKiByaHMpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuIGxocy0+Y29zdCA+IHJocy0+Y29zdDsKICAgIH0KfTsKCi8vIEZ1bmN0aW9uIHRvIHNvbHZlIFRyYXZlbGluZyBTYWxlc21hbiBQcm9ibGVtIHVzaW5nIEJyYW5jaCBhbmQgQm91bmQuCmludCBzb2x2ZShpbnQgY29zdE1hdHJpeFtOXVtOXSkKewogICAgLy8gQ3JlYXRlIGEgcHJpb3JpdHkgcXVldWUgdG8gc3RvcmUgbGl2ZSBub2RlcyBvZgogICAgLy8gc2VhcmNoIHRyZWU7CiAgICBwcmlvcml0eV9xdWV1ZTxOb2RlKiwgc3RkOjp2ZWN0b3I8Tm9kZSo+LCBjb21wPiBwcTsKCQogICAgdmVjdG9yPHBhaXI8aW50LCBpbnQ+ID4gdjsKICAgIC8vIGNyZWF0ZSBhIHJvb3Qgbm9kZSBhbmQgY2FsY3VsYXRlIGl0cyBjb3N0CgkvLyBUaGUgVFNQIHN0YXJ0cyBmcm9tIGZpcnN0IGNpdHkgaS5lLiBub2RlIDAKICAgIE5vZGUqIHJvb3QgPSBuZXdOb2RlKGNvc3RNYXRyaXgsIHYsIDAsIC0xLCAwKTsKCS8vIGdldCB0aGUgbG93ZXIgYm91bmQgb2YgdGhlIHBhdGggc3RhcnRpbmcgYXQgbm9kZSAwCiAgICByb290LT5jb3N0ID0gY2FsY3VsYXRlQ29zdChyb290LT5yZWR1Y2VkTWF0cml4KTsKCiAgICAvLyBBZGQgcm9vdCB0byBsaXN0IG9mIGxpdmUgbm9kZXM7CiAgICBwcS5wdXNoKHJvb3QpOwoKICAgIC8vIEZpbmRzIGEgbGl2ZSBub2RlIHdpdGggbGVhc3QgY29zdCwKICAgIC8vIGFkZCBpdHMgY2hpbGRyZW4gdG8gbGlzdCBvZiBsaXZlIG5vZGVzIGFuZAogICAgLy8gZmluYWxseSBkZWxldGVzIGl0IGZyb20gdGhlIGxpc3QuCiAgICB3aGlsZSghcHEuZW1wdHkoKSkKICAgIHsKICAgICAgICAvLyBGaW5kIGEgbGl2ZSBub2RlIHdpdGggbGVhc3QgZXN0aW1hdGVkIGNvc3QKICAgICAgICBOb2RlKiBtaW4gPSBwcS50b3AoKTsKCiAgICAgICAgLy8gVGhlIGZvdW5kIG5vZGUgaXMgZGVsZXRlZCBmcm9tIHRoZSBsaXN0IG9mCiAgICAgICAgLy8gbGl2ZSBub2RlcwogICAgICAgIHBxLnBvcCgpOwoKCQkvLyBpIHN0b3JlcyBjdXJyZW50IGNpdHkgbnVtYmVyCiAgICAgICAgaW50IGkgPSBtaW4tPnZlcnRleDsKCiAgICAgICAgLy8gaWYgYWxsIGNpdGllcyBhcmUgdmlzaXRlZAogICAgICAgIGlmKG1pbi0+bGV2ZWwgPT0gTiAtIDEpCiAgICAgICAgewogICAgICAgICAgICAvLyByZXR1cm4gdG8gc3RhcnRpbmcgY2l0eQogICAgICAgICAgICBtaW4tPnBhdGgucHVzaF9iYWNrKG1ha2VfcGFpcihpLCAwKSk7CgkJCS8vIHByaW50IGxpc3Qgb2YgY2l0aWVzIHZpc2l0ZWQ7CiAgICAgICAgICAgIHByaW50UGF0aChtaW4tPnBhdGgpOwoJCQkKCQkJLy8gcmV0dXJuIG9wdGltYWwgY29zdAogICAgICAgICAgICByZXR1cm4gbWluLT5jb3N0OwogICAgICAgIH0KCiAgICAgICAgLy8gZG8gZm9yIGVhY2ggY2hpbGQgb2YgbWluCiAgICAgICAgLy8gKGksIGopIGZvcm1zIGFuIGVkZ2UgaW4gc3BhY2UgdHJlZQogICAgICAgIGZvcihpbnQgaiA9IDA7IGogPCBOOyBqKyspCiAgICAgICAgewogICAgICAgICAgICBpZihtaW4tPnJlZHVjZWRNYXRyaXhbaV1bal0gIT0gSU5GKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAvLyBjcmVhdGUgYSBjaGlsZCBub2RlIGFuZCBjYWxjdWxhdGUgaXRzIGNvc3QKICAgICAgICAgICAgICAgIE5vZGUqIGNoaWxkID0gbmV3Tm9kZShtaW4tPnJlZHVjZWRNYXRyaXgsIG1pbi0+cGF0aCwgCgkJCQkJCQkJCQltaW4tPmxldmVsKzEsIGksIGopOwoKCQkJCS8qIENvc3Qgb2YgdGhlIGNoaWxkID0gCgkJCQkJY29zdCBvZiBwYXJlbnQgbm9kZSArIAoJCQkJCWNvc3Qgb2YgdGhlIGVkZ2UoaSwgaikgKwoJCQkJCWxvd2VyIGJvdW5kIG9mIHRoZSBwYXRoIHN0YXJ0aW5nIGF0IG5vZGUgagoJCQkJKi8KICAgICAgICAgICAgICAgIGNoaWxkLT5jb3N0ID0gbWluLT5jb3N0ICsgbWluLT5yZWR1Y2VkTWF0cml4W2ldW2pdICsgCiAgICAgICAgICAgICAgICAJCQkgIGNhbGN1bGF0ZUNvc3QoY2hpbGQtPnJlZHVjZWRNYXRyaXgpOwoKICAgICAgICAgICAgICAgIC8vIEFkZCBjaGlsZCB0byBsaXN0IG9mIGxpdmUgbm9kZXMKICAgICAgICAgICAgICAgIHBxLnB1c2goY2hpbGQpOwogICAgICAgICAgICB9CiAgICAgICAgfQoJCS8vIGZyZWUgbm9kZSBhcyB3ZSBoYXZlIGFscmVhZHkgc3RvcmVkIGVkZ2VzIChpLCBqKSBpbiB2ZWN0b3IKCQkvLyBTbyBubyBuZWVkIGZvciBwYXJlbnQgbm9kZSB3aGlsZSBwcmludGluZyBzb2x1dGlvbi4KICAgICAgICBmcmVlKG1pbik7CiAgICB9Cn0KCi8vIERyaXZlciBmdW5jdGlvbiB0byB0ZXN0IGFib3ZlIGZ1bmN0aW9ucwppbnQgbWFpbigpCnsKICAgIC8vIGNvc3QgbWF0cml4IGZvciB0cmF2ZWxpbmcgc2FsZXNtYW4gcHJvYmxlbS4KICAgIC8qaW50IGNvc3RNYXRyaXhbTl1bTl0gPQogICAgewogICAgICAgIHtJTkYsIDUsICAgSU5GLCA2LCAgIDUsICAgNH0sCiAgICAgICAgezUsICAgSU5GLCAyLCAgIDQsICAgMywgICBJTkZ9LAogICAgICAgIHtJTkYsIDIsICAgSU5GLCAxLCAgIElORiwgSU5GfSwKICAgICAgICB7NiwgICA0LCAgIDEsICAgSU5GLCA3LCAgIElORn0sCiAgICAgICAgezUsICAgMywgICBJTkYsIDcsICAgSU5GLCAzfSwKICAgICAgICB7NCwgICBJTkYsIElORiwgSU5GLCAzLCAgIElORn0KICAgIH07CiovCiAgICAvLyBjb3N0IDM0CiAgICBpbnQgY29zdE1hdHJpeFtOXVtOXSA9CiAgICB7CiAgICAgICAge0lORiwgMTAsICA4LCAgIDksICAgN30sCiAgICAgICAgezEwLCAgSU5GLCAxMCwgIDUsICAgNn0sCiAgICAgICAgezgsICAxMCwgICBJTkYsIDgsICAgOX0sCiAgICAgICAgezksICA1LCAgICA4LCAgIElORiwgNn0sCiAgICAgICAgezcsICA2LCAgICA5LCAgIDYsICAgSU5GfQogICAgfTsKCiAgICAvKi8vIGNvc3QgMTYKICAgIGludCBjb3N0TWF0cml4W05dW05dID0KICAgIHsKICAgICAgICB7SU5GLCAzLCAgIDEsICAgNSwgICA4fSwKICAgICAgICB7MywgICBJTkYsIDYsICAgNywgICA5fSwKICAgICAgICB7MSwgICA2LCAgIElORiwgNCwgICAyfSwKICAgICAgICB7NSwgICA3LCAgIDQsICAgSU5GLCAzfSwKICAgICAgICB7OCwgICA5LCAgIDIsICAgMywgICBJTkZ9CiAgICB9OyovCiAvKgogICAgLy8gY29zdCA4CiAgICBpbnQgY29zdE1hdHJpeFtOXVtOXSA9CiAgICB7CiAgICAgICAge0lORiwgMiwgICAxLCAgIElORn0sCiAgICAgICAgezIsICAgSU5GLCA0LCAgIDN9LAogICAgICAgIHsxLCAgIDQsICAgSU5GLCAyfSwKICAgICAgICB7SU5GLCAzLCAgIDIsICAgSU5GfQogICAgfTsKCiAgICAvL2Nvc3QgMTIKICAgIGludCBjb3N0TWF0cml4W05dW05dID0KICAgIHsKICAgICAgICB7SU5GLCA1LCAgIDQsICAgM30sCiAgICAgICAgezMsICAgSU5GLCA4LCAgIDJ9LAogICAgICAgIHs1LCAgIDMsICAgSU5GLCA5fSwKICAgICAgICB7NiwgICA0LCAgIDMsICAgSU5GfQogICAgfTsKKi8KICAgIGNvdXQgPDwgIlxuXG5Ub3RhbCBDb3N0IGlzICIgPDwgc29sdmUoY29zdE1hdHJpeCk7CgogICAgcmV0dXJuIDA7Cn0K