Dashboard - Qualification Round 2013 - Google Code Jam
Following an old map, you have stumbled upon the Dread Pirate Larry's secret treasure trove!
The treasure trove consists of N locked chests, each of which can only be opened by a key of a specific type. Furthermore, once a key is used to open a chest, it can never be used again. Inside every chest, you will of course find lots of treasure, and you might also find one or more keys that you can use to open other chests. A chest may contain multiple keys of the same type, and you may hold any number of keys.
You already have at least one key and your map says what other keys can be found inside the various chests. With all this information, can you figure out how to unlock all the chests?
For example, suppose the treasure trove consists of four chests as described below, and you began with exactly one key of type 1:
This is followed by a line containing K integers, representing the types of the keys that you start with.
After that, there will be N lines, each representing a single chest. Each line will begin with integers Ti and Ki, indicating the key type needed to open the chest and the number of keys inside the chest. These two integers will be followed by Ki more integers, indicating the types of the keys contained within the chest.
If there are multiple ways of opening all the chests, choose the "lexicographically smallest" way. In other words, you should choose to make C1 as small as possible, and if there are multiple ways of making C1 as small as possible, choose the one that makes C2 as small as possible, and so on.
If there is no way to open all the chests, you should instead output one line containing "Case #x: IMPOSSIBLE".
https://northanapon.wordpress.com/2013/04/18/google-code-jam-qualification-2013-treasure/
Pre-checking
If there is no valid solution, then don’t need to try. We can pre-check the number of keys and locks before doing anything else. Make sure we have enough numbers of key types for every lock. If so, the case is good to go.
http://ivoroshilin.com/2013/09/11/google-code-jam-qualification-round-2013-problem-d-treasure/
Following an old map, you have stumbled upon the Dread Pirate Larry's secret treasure trove!
The treasure trove consists of N locked chests, each of which can only be opened by a key of a specific type. Furthermore, once a key is used to open a chest, it can never be used again. Inside every chest, you will of course find lots of treasure, and you might also find one or more keys that you can use to open other chests. A chest may contain multiple keys of the same type, and you may hold any number of keys.
You already have at least one key and your map says what other keys can be found inside the various chests. With all this information, can you figure out how to unlock all the chests?
For example, suppose the treasure trove consists of four chests as described below, and you began with exactly one key of type 1:
Chest Number | Key Type To Open Chest | Key Types Inside --------------+--------------------------+------------------ 1 | 1 | None 2 | 1 | 1, 3 3 | 2 | None 4 | 3 | 2
You can open all the chests in this example if you do them in the order 2, 1, 4, 3. If you start by opening chest #1 first, then you will have used up your only key, and you will be stuck.
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case begins with a single line containing two positive integers K and N, representing the number of keys you start with and the number of chests you need to open.This is followed by a line containing K integers, representing the types of the keys that you start with.
After that, there will be N lines, each representing a single chest. Each line will begin with integers Ti and Ki, indicating the key type needed to open the chest and the number of keys inside the chest. These two integers will be followed by Ki more integers, indicating the types of the keys contained within the chest.
Output
For each test case, output one line containing "Case #x: C1 C2 ... CN", where x is the case number (starting from 1), and where Ci represents the index (starting from 1) of the ith chest that you should open.If there are multiple ways of opening all the chests, choose the "lexicographically smallest" way. In other words, you should choose to make C1 as small as possible, and if there are multiple ways of making C1 as small as possible, choose the one that makes C2 as small as possible, and so on.
If there is no way to open all the chests, you should instead output one line containing "Case #x: IMPOSSIBLE".
https://northanapon.wordpress.com/2013/04/18/google-code-jam-qualification-2013-treasure/
Pre-checking
If there is no valid solution, then don’t need to try. We can pre-check the number of keys and locks before doing anything else. Make sure we have enough numbers of key types for every lock. If so, the case is good to go.
http://ivoroshilin.com/2013/09/11/google-code-jam-qualification-round-2013-problem-d-treasure/
1. Check that the number of chests matches the number of corresponding key types. A simple arithmetic to count. Otherwise there is no solution as we don’t have enough keys to open all chests.
2. All vertices in a graph G should be reachable from vertex v0.
The restriction isn't annoying: it is a very strong clue indicating the nature of the solution (branch and bound with lexical enumeration).int N, K;
int initialKeys[40];
int chests[20][40];
int chestKeys[20];
int chestType[20];
vector<int> mem[1<<20];
void solve( ostream& cout ) {
// base case:
mem[0] = vector<int>(0);
const int INF = N*(N + 1);
// Try each of them:
for (int mask=1; mask <(1<<N); mask++) {
// A single element containing infinite is our way to mark a state
// as having no possible solution.
mem[mask] = vector<int>(1, INF);
// Count the number of keys of each type:
map<int, int> keys;
for (int i = 0; i < K; i++) {
keys[ initialKeys[i] ]++;
}
for (int j=0; j < N; j++) {
if ( !( (1<<j) & mask ) ) {
keys[ chestType[j] ]--;
for (int k = 0; k < chestKeys[j]; k++) {
keys[ chests[j][k] ]++;
}
}
}
// don't worry, if any number of keys is negative, this state will
// never be reached from an upper state, so its result would not matter
for (int j=0; j < N; j++) {
if ( (1<<j) & mask ) {
if (keys[ chestType[j] ] > 0) { // We can open chest j.
// Find out what happens if we open chest j:
vector<int> other = mem[ mask - (1<<j) ];
// If there is a solution, append j:
if ( (other.size() == 0) || (other[0] != INF) ) {
vector<int> nw( other.size() + 1);
nw[0] = j+1;
for (int i=1; i<nw.size(); i++) {
nw[i] = other[i-1];
}
// Remember the best solution so far.
mem[mask] = std::min( mem[mask], nw) ;
}
}
}
}
}
// Result is f( (1<<N) - 1):
vector<int> &res = mem[ (1<<N) - 1];
if (res[0] != INF) {
cout << res[0];
for (int i = 1; i < N; i++) {
cout << " "<<res[i];
}
} else {
cout << "IMPOSSIBLE";
}
cout << endl;
}
Read full article from Dashboard - Qualification Round 2013 - Google Code Jam