Data Structures and Algorithms Algorithms in C++: Jordi Petit Salvador Roura Albert Atserias
Data Structures and Algorithms Algorithms in C++: Jordi Petit Salvador Roura Albert Atserias
ALGORITHMS IN C++
Jordi Petit Salvador Roura Albert Atserias
15 de febrer de 2017
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
while (getline(cin, s)) {
istringstream ss(s);
int sum = 0;
int x;
while (ss >> x) sum += x;
cout << sum << endl;
} }
Stacks.
Reads a sequence of numbers and writes it backwards.
#include <stack>
#include <iostream>
using namespace std;
int main() {
stack<int> s;
int x;
while (cin >> x) s.push(x);
while (not s.empty()) {
cout << s.top() << endl;
s.pop();
} }
Queues.
Reads a sequence of numbers and writes it straight.
#include <queue>
#include <iostream>
using namespace std;
int main() {
queue<int> q;
int x;
while (cin >> x) q.push(x);
while (not q.empty()) {
cout << q.front() << endl;
q.pop();
} }
Priority queues.
Reads a sequence of numbers and writes it in decreasing order.
#include <queue>
#include <iostream>
using namespace std;
int main() {
priority_queue<int> pq;
int x;
while (cin >> x) pq.push(x);
while (not pq.empty()) {
cout << pq.top() << endl;
pq.pop();
} }
#include <queue>
#include <iostream>
using namespace std;
int main() {
priority_queue<int, vector<int>, greater<int>> pq;
int x;
while (cin >> x) pq.push(x);
while (not pq.empty()) {
cout << pq.top() << endl;
pq.pop();
} }
Sets.
Reads two sequences of numbers ended with 0 and writes their intersection.
#include <set>
#include <iostream>
#include <string>
using namespace std;
int main() {
set<int> s1, s2;
int x;
cin >> x;
while (x != 0) {
s1.insert(x);
cin >> x;
}
cin >> x;
while (x != 0) {
s2.insert(x);
cin >> x;
}
for (set<int>::iterator it = s1.begin(); it != s1.end(); ++it) {
if (s2.find(*it) != s2.end()) cout << *it << endl;
} }
Maps.
Reads a sequence of words and, for each word, in alphabetical order, writes the number of times it
appears.
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
map<string, int> m;
string x;
while (cin >> x) ++m[x];
for (map<string, int>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << " " << it->second << endl;
} }
#include <vector>
#include <set>
#include <iostream>
using namespace std;
int main() {
// read a vector from input
vector<int> v;
int x;
while (cin >> x) v.push_back(x);
// write all elements of v to output
for (int y : v) cout << y << "endl";
// double all elements of v (note the reference to modify the elements!!!)
for (int& y : v) y *= 2;
// write all elements of v again
for (int y : v) cout << y << endl;
Unordered sets.
Reads two sequences of numbers ended with 0 and writes their intersection. This code uses C++11.
#include <unordered_set>
#include <iostream>
#include <string>
using namespace std;
int main() {
unordered_set<int> s1, s2;
int x;
cin >> x;
while (x != 0) {
s1.insert(x);
cin >> x;
}
cin >> x;
while (x != 0) {
s2.insert(x);
cin >> x;
}
for (auto x : s1) {
if (s2.find(x) != s2.end()) cout << x << endl;
} }
1.10 Unordered dictionaries: unordered_map
Unordered maps.
Reads a sequence of words and, for each word, prints the number of times it appears. Since an
unordered map is used, the order of the output is undefined. This code uses C++11.
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
int main() {
unordered_map<string, int> m;
string x;
while (cin >> x) ++m[x];
for (auto elem : m) {
cout << elem.first << " " << elem.second << endl;
} }
#include <unordered_set>
using namespace std;
struct Point {
int x, y, z;
struct Hash {
size_t operator() (const Point& p) const {
return hash<int>()(p.x) + hash<int>()(p.y) + hash<int>()(p.z);
}
};
};
int main() {
unordered_set<Point, Point::Hash> cloud;
cloud.insert({5,2,3});
}
2
Sorting
Selection Sort.
Bubblesort.
2.6 Mergesort — 1
2.7 Mergesort — 2
Mergesort (version 2).
Cuts the recursion when the subvector is ”small enough”at which point it uses insertion sort.
2.8 Mergesort — 3
2.9 Quicksort — 1
2.10 Quicksort — 2
2.11 Quicksort — 3
2.12 Heapsort — 1
2.13 Heapsort — 2
Heapsort.
3.1 Tables
#include <utility>
#include <vector>
using namespace std;
private:
vector<Pair> t;
public:
...............................................................................................
Assigns info to key. If the key belongs to the dictionary already, the associated information is
modified.
Worst-case cost: Θ(n).
...............................................................................................
void assign (const Key& key, const Info& info) {
int i = find(key);
if (i < t.size()) {
t[i].second = info;
} else {
t.push_back(Pair(key, info));
} }
...............................................................................................
Erases key and its associated information from the dictionary. If the key does not belong to the
dictionary the dictionary does not change.
Worst-case cost: Θ(n).
...............................................................................................
void erase (const Key& key) {
int i = find(key);
if (i < t.size()) {
t[i] = t[t.size() - 1];
t.pop_back();
} }
...............................................................................................
Returns a reference to the information associated to key. Throws a precondition exception if the
key does not belong to the dictionary.
Worst-case cost: Θ(n).
...............................................................................................
Info& query (const Key& key) {
int i = find(key);
if (i < t.size()) {
return t[i].second;
} else {
throw "Key does not exist.";
} }
...............................................................................................
Determines if the dictionary contains key .
Worst-case cost: Θ(n).
...............................................................................................
bool contains (const Key& key) {
return find(key) < t.size();
}
...............................................................................................
Returns the size of the dictionary (i.e. the number of keys that belong to it).
Worst-case cost: Θ(1).
...............................................................................................
int size() {
return t.size();
}
private:
...............................................................................................
Returns the position of key in the table, or t.size if it is not there.
Worst-case cost: Θ(n).
...............................................................................................
int find (const Key& key) {
int i = 0;
while (i < t.size() and t[i].first != key) ++i;
return i;
}
};
3.2 Lists
#include <utility>
#include <list>
using namespace std;
private:
public:
...............................................................................................
Constructor. Creates an empty dictionary.
Worst-case cost: Θ(1).
...............................................................................................
Dictionary () {
n = 0;
}
...............................................................................................
Assigns info to key. If the key belongs to the dictionary already, the associated information is
modified.
Worst-case cost: Θ(n).
...............................................................................................
void assign (const Key& key, const Info& info) {
iter p = find(key);
if (p != li.end()) {
p->second = info;
} else {
li.push_back(Pair(key, info));
++n;
} }
...............................................................................................
Erases key and its associated information from the dictionary. If the key does not belong to the
dictionary the dictionary does not change.
Worst-case cost: Θ(n).
...............................................................................................
void erase (const Key& key) {
iter p = find(key);
if (p != li.end()) {
li.erase(p);
--n;
} }
...............................................................................................
Returns a reference to the information associated to key. Throws a precondition exception if the
key does not belong to the dictionary.
Worst-case cost: Θ(n).
...............................................................................................
Info& query (const Key& key) {
iter p = find(key);
if (p != li.end()) {
return p->second;
} else {
throw "Key does not exist";
} }
...............................................................................................
Determines if the dictionary contains key .
Worst-case cost: Θ(n).
...............................................................................................
bool contains (const Key& key) {
return find(key) != li.end();
}
...............................................................................................
Returns the size (i.e. number of keys) of the dictionary.
Worst-case cost: Θ(1).
...............................................................................................
int size() {
return n;
}
private:
...............................................................................................
Returns the position of c in the list, or li.end() if it is not there.
Worst-case cost: Θ(n).
...............................................................................................
iter find (const Key& c) {
iter p = li.begin();
while (p != li.end() and p->first != c) ++p;
return p;
}
};
#include <utility>
#include <list>
#include <vector>
private:
public:
...............................................................................................
Constructor. Creates an empty dictionary.
Worst-case cost: Θ( M ).
...............................................................................................
Dictionary (int M = 1009)
: t(M), n(0), M(M) { }
...............................................................................................
Assigns info to key. If the key belongs to the dictionary already the associated information is
modified.
Worst-case cost: Θ(n).
Average-case cost: Θ(1 + n/M ).
...............................................................................................
void assign (const Key& key, const Info& info) {
int h = hash(key) % M;
iter p = find(key, t[h]);
if (p != t[h].end()) {
p->second = info;
} else {
t[h].push_back(Pair(key, info));
++n;
} }
...............................................................................................
Erases key and its associated information from the dictionary. If the key does not belong to the
dictionary, nothing changes.
Worst-case cost: Θ(n).
Average-case cost: Θ(1 + n/M ).
...............................................................................................
void erase (const Key& key) {
int h = hash(key) % M;
iter p = find(key, t[h]);
if (p != t[h].end()) {
t[h].erase(p);
--n;
} }
...............................................................................................
Returns a reference to the information associated to key. Throws a precondition exception if the
key does not belong to the dictionary.
Worst-case cost: Θ(n).
Average-case cost: Θ(1 + n/M ).
...............................................................................................
Info& query (const Key& key) {
int h = hash(key) % M;
iter p = find(key, t[h]);
if (p != t[h].end()) {
return p->second;
} else {
throw "Key does not exist";
} }
...............................................................................................
Determines if the dictionary contains key .
Worst-case cost: Θ(n).
Average-case cost: Θ(1 + n/M ).
...............................................................................................
bool contains (const Key& key) {
int h = hash(key) % M;
iter p = find(key, t[h]);
return p != t[h].end();
}
...............................................................................................
Returns the size (i.e. number of keys) of the dictionary.
Worst-case cost: Θ(1). Average-case cost: Θ(1).
...............................................................................................
int size () {
return n;
}
private:
...............................................................................................
Finds key in the list and returns an iterator pointing to it, or pointing to end() if it is not there.
...............................................................................................
static iter find (const Key& key, list<Pair>& L) {
iter p = L.begin();
while (p != L.end() and p->first != key) ++p;
return p;
}
};
private:
struct Node {
Key key;
Info info;
Node* left; // Pointer to left child
Node* right; // Pointer to right child
public:
...............................................................................................
Constructor. Creates an empty dictionary.
Worst-case cost: Θ(1).
...............................................................................................
Dictionary () {
n = 0;
root = nullptr;
}
...............................................................................................
Copy constructor. Makes a copy.
Worst-case cost: Θ(n).
...............................................................................................
Dictionary (const Dictionary& d) {
n = d.n;
root = copy(d.root);
}
...............................................................................................
Assignment operator.
Worst-case cost: Θ(n + d.n).
...............................................................................................
Dictionary& operator= (const Dictionary& d) {
if (&d != this) {
free(root);
n = d.n;
root = copy(d.root);
}
return *this;
}
...............................................................................................
Destructor.
Worst-case cost: Θ(n).
...............................................................................................
~Dictionary () {
free(root);
}
...............................................................................................
Assign info to key.
Worst-case cost: Θ(h).
...............................................................................................
void assign (const Key& key, const Info& info) {
assign(root, key, info);
}
...............................................................................................
Erases key and its associated information. If the key does not belong to the dictionary, nothing
changes.
Worst-case cost: Θ(h).
...............................................................................................
void erase (const Key& key) {
erase_3(root, key);
}
...............................................................................................
Returns a reference to the information associated to key. Throws a precondition exception if the
key does not belong to the dictionary.
Worst-case cost: Θ(h).
...............................................................................................
Info& query (const Key& key) {
if (Node* p = find(root, key)) {
return p->info;
} else {
throw "Key does not exist";
} }
...............................................................................................
Determines if the dictionary contains key.
Worst-case cost: Θ(h).
...............................................................................................
bool contains (const Key& key) {
return find(root, key);
}
...............................................................................................
Returns the size (i.e. number of keys) of the dictionary.
Worst-case cost: Θ(1).
...............................................................................................
int size () {
return n;
}
private:
...............................................................................................
Deletes the tree pointed by p.
Worst-case cost: Θ(s) where s is the number of nodes in the tree pointed by p.
...............................................................................................
static void free (Node* p) {
if (p) {
free(p->left);
free(p->right);
delete p;
} }
...............................................................................................
Returns a pointer to a copy of the tree pointed by p.
Worst-case cost: Θ(s) where s is the number of nodes in the tree pointed by p.
...............................................................................................
static Node* copy (Node* p) {
return p ? new Node(p->key, p->info, copy(p->left), copy(p->right)) : nullptr;
}
...............................................................................................
Returns a pointer to the node of the tree pointed by p that contains key, or nullptr if the key is
not there.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
static Node* find (Node* p, const Key& key) {
if (p) {
if (key < p->key) {
return find(p->left, key);
} else if (key > p->key) {
return find(p->right, key);
} }
return p;
}
...............................................................................................
Assigns info to key if the key belongs to the tree pointed by p. Otherwise adds a new node into
the tree pointed by p with the key and the associated information.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
void assign (Node*& p, const Key& key, const Info& info) {
if (p) {
if (key < p->key) {
assign(p->left, key, info);
} else if (key > p->key) {
assign(p->right, key, info);
} else {
p->info = info;
}
} else {
p = new Node(key, info, nullptr, nullptr);
++n;
} }
...............................................................................................
Returns a pointer to the node that contains the minimum key in the tree rooted at p. Assumes
that p is not nullptr.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
static Node* minimum (Node* p) {
return p->left ? minimum(p->left) : p;
}
...............................................................................................
Returns a pointer to the node that contains the maximum key in the tree rooted at p. Assumes
that p is not nullptr.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
static Node* maximum (Node* p) {
return p->right ? maximum(p->right) : p;
}
...............................................................................................
Deletion version 1: Deleting a node with at least one empty child is easy. When both children
are non-empty, hangs the left child as the new left child of the minimum of the right child.
Drawback: trees degrade quickly.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
void erase_1 (Node*& p, const Key& key) {
if (p) {
if (key < p->key) {
erase_1(p->left, key);
} else if (key > p->key) {
erase_1(p->right, key);
} else {
Node* q = p;
if (!p->left) p = p->right;
else if (!p->right) p = p->left;
else {
Node* m = minimum(p->right);
m->left = p->left;
p = p->right;
}
delete q; --n;
} } }
...............................................................................................
Deletion version 2: Deleting a node with at least one empty child is easy. When both children
are non-empty, copies the minimum of the right child to the node that should disappear and
proceeds to deleting the minimum of the right child (which does not have left child for sure).
Drawback: copies keys and informations, not pointers.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
void erase_2 (Node*& p, const Key& key) {
if (p) {
if (key < p->key) {
erase_2(p->left, key);
} else if (key > p->key) {
erase_2(p->right, key);
} else if (!p->left) {
Node* q = p; p = p->right;
delete q; --n;
} else if (!p->right) {
Node* q = p; p = p->left;
delete q; --n;
} else {
Node* m = minimum(p->right);
p->key = m->key; p->info = m->info;
erase_2(p->right, m->key);
} } }
...............................................................................................
Deletion version 3: Deleting a node with at least one empty child is easy. When both children are
non-empty, calls extract_minimum which extracts the minimum of the right child and returns
a pointer to it. This node is placed where the node that should disappear was, which is finally
deleted.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
void erase_3 (Node*& p, const Key& key) {
if (p) {
if (key < p->key) {
erase_3(p->left, key);
} else if (key > p->key) {
erase_3(p->right, key);
} else {
Node* q = p;
if (!p->left) p = p->right;
else if (!p->right) p = p->left;
else {
Node* m = extract_minimum(p->right);
m->left = p->left; m->right = p->right;
p = m;
}
delete q; --n;
} } }
...............................................................................................
Extracts the node that contains the minimum element from the tree pointed by p. Returns a
pointer to it.
Worst-case cost: Θ(t) where t is the height of the tree pointed by p.
...............................................................................................
Node* extract_minimum (Node*& p) {
if (p->left) {
return extract_minimum(p->left);
} else {
Node* q = p;
p = p->right;
return q;
} }
};
3.5 AVL Trees
private:
struct Node {
Key key;
Info info;
Node* left; // Pointer to left child
Node* right; // Pointer to right child
int height; // Height of the tree
public:
Dictionary () {
n = 0;
root = nullptr;
}
Dictionary (Dictionary& d) {
n = d.n;
root = copy(d.root);
}
~Dictionary () {
free(root);
}
int size() {
return n;
}
private:
};
4
Priority Queues
#include "eda.hh"
private:
public:
...............................................................................................
Constructor. Creates an empty priority queue.
Cost: Θ(1).
...............................................................................................
CuaPrio () {
v.push_back(Elem());
}
...............................................................................................
Insert a new element.
Cost: Θ(log n).
...............................................................................................
void insert (const Elem& x) {
v.push_back(x);
shift_up(size());
}
...............................................................................................
Remove and return the minimum elemenv.
Cost: Θ(log n).
...............................................................................................
Elem remove_min () {
if (empty()) throw "Priority queue is empty";
Elem x = v[1];
v[1] = v.back();
v.pop_back();
shift_down(1);
return x;
}
...............................................................................................
Returns the minimum elemenv.
Cost: Θ(1).
...............................................................................................
Elem minimum () {
if (empty()) throw "Priority queue is empty";
return v[1];
}
...............................................................................................
Returns the size of the priority queue.
Cost: Θ(1).
...............................................................................................
int size () {
return v.size() - 1;
}
...............................................................................................
Indicates if the priority queue is empty.
Cost: Θ(1).
...............................................................................................
bool empty () {
return size() == 0;
}
private:
...............................................................................................
Shift a node up in the tree, as long as needed.
...............................................................................................
void shift_up (int i) {
if (i != 1 and v[i/2] > v[i]) {
swap(v[i], v[i/2]);
shift_up(i/2);
} }
...............................................................................................
Shift a node down in the tree, as long as needed.
...............................................................................................
void shift_down (int i) {
int n = size();
int c = 2*i;
if (c <= n) {
if (c+1 <= n and v[c+1] < v[c]) c++;
if (v[i] > v[c]) {
swap(v[i],v[c]);
shift_down(c);
} } }
};
#include "eda.hh"
private:
public:
...............................................................................................
Constructor. Creates an empty priority queue.
Cost: Θ(1).
...............................................................................................
PriorityQueue () {
v.push_back(Elem());
}
...............................................................................................
Inserts a new element.
Cost: Θ(log n).
...............................................................................................
void insert (const Elem& x) {
v.push_back(x);
int i = size();
while (i != 1 and v[i/2] > x) {
v[i] = v[i/2];
i = i/2;
}
v[i] = x;
}
...............................................................................................
Removes and returns the minimum element.
Cost en el cas pitjor: Θ(log n).
...............................................................................................
Elem remove_min () {
if (empty()) throw "Priority queue is empty";
int n = size();
Elem e = v[1], x = v[n];
v.pop_back(); --n;
int i = 1, c = 2*i;
while (c <= n) {
if (c+1 <= n and v[c+1] < v[c]) ++c;
if (x <= v[c]) break;
v[i] = v[c];
i = c;
c = 2*i;
}
v[i] = x;
return e;
}
...............................................................................................
Returns the minimum.
Cost: Θ(1).
...............................................................................................
Elem minimum () {
if (empty()) throw "Priority queue is empty";
return v[1];
}
...............................................................................................
Returns the size of the priority queue.
Cost: Θ(1).
...............................................................................................
int size () {
return v.size() - 1;
}
...............................................................................................
Indicates if the queue is empty.
Cost: Θ(1).
...............................................................................................
bool empty () {
return size() == 0;
}
};
5
Graphs
#ifndef graf_hh
#define graf_hh
#include <vector>
#include <list>
#endif
Depth-first search.
The function returns the list of vertices according to its order of visit in a depth-first search.
This code uses C++11.
#include <stack>
#include "eda.hh"
#include "graph.hh"
....................................................................................................
Recursive version. Cost: Θ(|V | + | E|).
....................................................................................................
void dfs_rec (const graph& G, int u, vector<boolean>& vis, list<int>& L) {
if (not vis[u]) {
vis[u] = true; L.push_back(u);
for (int v : G[u]) {
dfs_rec(G, v, vis, L);
} } }
....................................................................................................
Iterative version: the order of visit is different than that of the recursive version because the neighbors
leave the stack in reverse order. Cost: Θ(|V | + | E|).
....................................................................................................
list<int> dfs_ite (const graph& G) {
int n = G.size();
list<int> L;
stack<int> S;
vector<boolean> vis(n, false);
#include <queue>
#include "eda.hh"
#include "graph.hh"
....................................................................................................
Direct version: same as iterative dfs but with queue instead of stack; enqueues each vertex as many
times as its indegree. Cost: Θ(|V | + | E|).
....................................................................................................
list<int> bfs_1 (const graph& G) {
int n = G.size();
list<int> L;
queue<int> Q;
vector<boolean> vis(n, false);
....................................................................................................
Better version: avoids enqueuing a vertex more than once. Cost: Θ(|V | + | E|).
....................................................................................................
list<int> bfs_2 (const graph& G) {
int n = G.size();
list<int> L;
queue<int> Q;
vector<boolean> enc(n, false);
Topological sort.
Given a directed acyclic graph, returns a list with its vertices sorted in topological sort, that is, in
such a way that a vertex v does not appear before a vertex u if there is a path from u to v. Cost:
Θ(|V | + | E|).
This code uses C++11.
#include <stack>
#include "eda.hh"
#include "graph.hh"
stack<int> S;
for (int u = 0; u < n; ++u) {
if (ge[u] == 0) {
S.push(u);
} }
list<int> L;
while (not S.empty()) {
int u = S.top(); S.pop();
L.push_back(u);
for (int v : G[u]) {
if (--ge[v] == 0) {
S.push(v);
} } }
return L;
}
#include "eda.hh"
Prim’s algorithm.
Edges are inserted in the priority queue with their signs reversed. Alternatively we could have
redefined the order of the priority queue. Running time is Θ((|V | + | E|) log(|V |)).
#include "eda.hh"
6.1 n Queens — 1
n-queens problem.
Write an algorithm that writes all possible ways of placing n queens on an n × n chessboard in such
a way that no queen threatens another.
First (naive) version.
#include "eda.hh"
class NQueens {
void recursive(int i) {
if (i==n) {
write();
} else {
for (int j = 0; j < n; ++j) {
T[i] = j;
if (legal(i)) {
recursive(i+1);
} } } }
void write() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << (T[i]==j ? "O " : "* ") ;
}
cout << endl;
}
cout << endl;
}
public:
NQueens(int n) {
this->n = n;
T = vector<int>(n);
recursive(0);
}
};
....................................................................................................
Main program
....................................................................................................
int main() {
int n = readint();
NQueens r(n);
}
6.2 n Queens — 2
n-queens problem.
Write an algorithm that writes all possible ways of placing n queens in an n × n chessboard in such
a way that no queens threatens another.
This is a less naive solution.
#include "eda.hh"
class NQueens {
void recursive(int i) {
if (i == n) {
write();
} else {
for (int j = 0; j < n; ++j) {
if (not mc[j] and not md1[diag1(i, j)]
and not md2[diag2(i, j)]) {
T[i] = j;
mc[j] = true;
md1[diag1(i, j)] = true;
md2[diag2(i, j)] = true;
recursive(i+1);
mc[j] = false;
md1[diag1(i, j)] = false;
md2[diag2(i, j)] = false;
} } } }
void write() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << (T[i] == j ? "O " : "* ") ;
}
cout << endl;
}
cout << endl;
}
public:
NQueens(int n) {
this->n = n;
T = vector<int>(n);
mc = vector<boolean>(n, false);
md1 = vector<boolean>(2*n-1, false);
md2 = vector<boolean>(2*n-1, false);
recursive(0);
}
};
....................................................................................................
Main program
....................................................................................................
int main () {
int n = readint();
NQueens r(n);
}
6.3 n Queens — 3
n-queens problem.
Write an algorithm that writes a way of placing n queens on an n × n chessboard in such a way that
no queen threatens another.
#include "eda.hh"
class NQueens {
void recursive(int i) {
if (i == n) {
found = true;
write();
} else {
for (int j = 0; j < n and not found; ++j) {
if (not mc[j] and not md1[diag1(i, j)]
and not md2[diag2(i, j)]) {
T[i] = j;
mc[j] = true;
md1[diag1(i, j)] = true;
md2[diag2(i, j)] = true;
recursive(i+1);
mc[j] = false;
md1[diag1(i, j)] = false;
md2[diag2(i, j)] = false;
} } } }
void write() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << (T[i] == j ? "O " : "* ") ;
}
cout << endl;
}
cout << endl;
}
public:
NQueens(int n) {
this->n = n;
T = vector<int>(n);
mc = vector<boolean>(n, false);
md1 = vector<boolean>(2*n-1, false);
md2 = vector<boolean>(2*n-1, false);
found = false;
recursive(0);
}
};
....................................................................................................
Main program
....................................................................................................
int main() {
int n = readint();
NQueens r(n);
}
#include "eda.hh"
class LatinSquare {
public:
LatinSquare(int n) {
this->n = n;
Q = matrix<int>(n, n);
F = matrix<boolean>(n, n, true);
C = matrix<boolean>(n, n, true);
recursive(0);
}
};
....................................................................................................
Main program
....................................................................................................
int main () {
int n = readint();
LatinSquare qll(n);
}
Knight-jumps problem.
A knight is placed on a given square of an n × n chessboard. Write an algorithm to determine if there
is a way to visit every square of the board by moving it n2 − 1 times.
#include "eda.hh"
class KnightJumps {
public:
bool has_a_solution() {
return found;
}
board solution() {
return S;
}
};
....................................................................................................
Main program. A solution for 6x6 can be found starting at 0,1 (it takes a while).
....................................................................................................
int main () {
int n,ox,oy;
cin >> n >> ox >> oy;
KnightJumps kj(n,ox,oy);
if (kj.has_a_solution()) cout << kj.has_a_solution() << endl;
}
6.6 Task Scheduling
Scheduling problem.
A boss has n workers for n tasks. The time that worker i takes to complete task j is given by T [i ][ j].
He wants to assign a task to each worker so as to minimize the total time span.
#include "eda.hh"
class Scheduling {
public:
Scheduling(time_matrix T) {
this->T = T;
n = T.rows();
assig = vector<int>(n, -1);
done = vector<boolean>(n, false);
best = infinity;
recursive(0, 0);
}
vector<int> solution() {
return sol;
}
double cost() {
return best;
}
};
....................................................................................................
Main program reads n, creates the time matrix, the solver, runs it, and writes the solution.
....................................................................................................
int main () {
int n = readint();
time_matrix M = randmatrix(n);
cout << M;
Scheduling tasks(M);
cout << tasks.cost() << endl;
cout << tasks.solution() << endl;
}
#include "eda.hh"
#include <algorithm>
class HamiltonianGraph {
Graph G; // the graph
int n; // number of vertices
bool found; // indicates if a cycle has been found
vector<int> s; // next of each vertex (−1 if not used)
vector<int> S; // solution (if found)
public:
HamiltonianGraph(Graph G) {
this->G = G;
n = G.size();
s = vector<int>(n, -1);
found = false;
recursive(0, 1);
}
bool has_a_solution() {
return found;
}
vector<int> solution() {
return S;
}
};
....................................................................................................
Reads the graph: first the number of vertices; next, for each vertex, its degree and its adjacency list.
....................................................................................................
Graph read_graph() {
Graph G;
int n = readint();
G = Graph(n);
for (int u = 0; u < n; u++) {
int d = readint();
for (int i = 0; i < d; i++) {
G[u].push_back(readint());
}
sort(G[u].begin(), G[u].end());
}
return G;
}
....................................................................................................
Main program: reads the graph, creates the solver, and runs it.
....................................................................................................
int main() {
HamiltonianGraph ham(read_graph());
if (ham.has_a_solution()) {
vector<int> s = ham.solution();
cout << 0 << " ";
for (int u = s[0]; u != 0; u = s[u]) {
cout << u << " ";
}
cout << endl;
} }
#include "eda.hh"
class TSP {
public:
TSP(distance_matrix M) {
this->M = M;
n = M.rows();
s = vector<int>(n, -1);
sol = vector<int>(n);
best = infinity;
recursive(0, 1, 0);
}
vector<int> solution () {
return sol;
}
int next(int x) {
return sol[x];
}
double cost() {
return best;
}
};
....................................................................................................
Main program reads n, creates a distance matrix with randomly placed cities, runs the traveling
salesman problem, and writes the cost of the best solution.
....................................................................................................
int main () {
int n = readint();
vector<double> x = randvector(n);
vector<double> y = randvector(n);
distance_matrix M = distance_matrix(n, n);
for (int u = 0; u < n; ++u) {
for (int v = 0; v < n; ++v) {
M[u][v] = sqrt((x[u]-x[v])*(x[u]-x[v]) + (y[u]-y[v])*(y[u]-y[v]));
} }
double t = now();
TSP tsp(M);
t = now() - t;
cout << "temps: " << t << endl;
cout << tsp.cost() << endl;
cout << tsp.solution() << endl;
}
6.9 Knapsack — 1
Knapsack problem.
We have got a knapsack that can hold up to C units of weight and up to n objects. The i-th object has
weight p[i ] and value v[i ]. Our goal is to choose which objects to place in the knapsack in such a way
that the sum of their values is maximized subject to the constraint that the sum of their weights does
not exceed C. Objects cannot be split.
Backtracking solution without lower bound.
#include "eda.hh"
class Knapsack {
public:
vector<boolean> solution() {
return sol;
}
double value() {
return best;
}
};
....................................................................................................
Main program: reads the number of objects, sets the weights and values at random, sets the capacity
to 0.4 the number of objects, creates the solver, runs it, and writes the solution.
....................................................................................................
int main () {
int n = readint();
vector<double> p = randvector(n);
vector<double> v = randvector(n);
double C = 0.4*n;
cout << v << endl << p << endl << C << endl;
6.10 Knapsack — 2
Knapsack problem.
We have got a knapsack that can hold up to C units of weight and up to n objects. The i-th object has
weight p[i ] and value v[i ]. Our goal is to choose which objects to place in the knapsack in such a way
that the sum of their values is maximized subject to the constraint that the sum of their weights does
not exceed C. Objects cannot be split.
Backtracking solution with lower bound: we take into account the maximum value contribution that
the remaining objects could bring (even if they exceed the capacity).
A clever sorting of the objects might improve the algorithm.
#include "eda.hh"
class Knapsack {
public:
vector<boolean> solution() {
return sol;
}
double value() {
return best;
}
};
....................................................................................................
Main program: reads the number of objects, sets the weights and values at random, sets the capacity
to 0.4 the number of objects, creates the solver, runs it, and writes the solution.
....................................................................................................
int main () {
int n = readint();
vector<double> p = randvector(n);
vector<double> v = randvector(n);
double C = 0.4*n;
cout << v << endl << p << endl << C << endl;
Knapsack k(n,p,v,C);
cout << k.value() << endl;
cout << k.solution() << endl;
}
A
Macros
A.1 eda.hh
This is non-polished code.
Data Structures and Algorithms.
Jordi Petit Salvador Roura July 2010 Translated by AA in September 2013
#ifndef eda_hh
#define eda_hh
....................................................................................................
Standard inclusions
....................................................................................................
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <limits>
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <sys/resource.h>
....................................................................................................
Definition of boolean type. The boolean type is an int, but it is used as if it were a bool. The purpose of
this definition is to make vectors of booleans that are fast. A vector¡bool¿ is slow because it works at
the bit level.
....................................................................................................
typedef int boolean;
....................................................................................................
Definition of the null pointer null. In C++ a null pointer is simply a zero.
....................................................................................................
#define null 0
....................................................................................................
Definition of the generic class matrix. Useful to make bidimensional tables without using vectors of
vectors. The downside is that the numbers of rows and columns are fixed.
....................................................................................................
template <typename T>
class matrix {
int r,c;
vector<vector<T> > t;
public:
matrix() :
r(0), c(0) { }
vector<T>& operator[](int i) {
return t[i];
}
....................................................................................................
Functions to read basic types.
....................................................................................................
inline int readint () { int n; cin >> n; return n; }
inline char readchar () { char n; cin >> n; return n; }
inline bool readbool () { bool n; cin >> n; return n; }
inline double readdouble () { double n; cin >> n; return n; }
....................................................................................................
Defines infinity as a double that is bigger than any other double (except, obviously infinity).
....................................................................................................
const double infinity = numeric_limits<double>::infinity();
....................................................................................................
Defines maxint as the largest representable integer.
....................................................................................................
const int maxint = numeric_limits<int>::max();
....................................................................................................
Functions to generate random numbers.
....................................................................................................
// Returns a random real in [0, 1).
inline double randdouble() {
return rand() / double(RAND_MAX);
}
....................................................................................................
Functions to measure CPU time.
....................................................................................................
inline double now() {
// This works in Linux, I do not know for other systems.
struct rusage u;
getrusage(RUSAGE_SELF, &u);
return
u.ru_utime.tv_sec + u.ru_stime.tv_sec
+(u.ru_utime.tv_usec + u.ru_stime.tv_usec)/1000000.0;
}
....................................................................................................
Macro to iterate over all the elements in a container.
....................................................................................................
#define foreach(it,c) for (__typeof((c).begin()) it=(c).begin(); it!=(c).end(); ++it)
....................................................................................................
ErrorPrec and ErrorImpl are thrown exceptions. Error is a common basic class, useful to catch both.
This is the only place where inheritance is used in the course.
....................................................................................................
class Error {
private:
string err;
public:
Error(string s) : err(s) {}
string error() const {return err;}
};
#endif