In how many ways can you put the numbers 1-16 into 16 sectors of circle such that the sum of any 3 consecutive sectors is less than 27 ? Any two sectors cannot have the same number.
[Source : AoPS]
I wanted to solve this problem using programming. The program I wrote is too slow (possibly 10^12 permutations being checked) despite my attempts at optimisation.
Logic behind my program (Filling sectors sequentially)
First I made sector[0] = 1 as a pivot. The remaining numbers (2-15) will be arranged in the remaining sectors with respect to this pivot. Then we fill sector[1]...sector[15] and stop when sector[0] is reached.
Given an empty sector,
If we don't know the values in the 2 previous sectors, try all possible numbers while keeping sum below 27.
Else find the sum of the 2 previous sectors, and for the current sector, try only the numbers that keep the sum below 27.
Move to next sector.
Stop when we reach sector with index 0. In that case check sum of sector 14, 15, 0 and 15, 0, 1.
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
unordered_map<int, int> UpdatedMap(unordered_map<int, int> Available, int key) {
// Removes key from map and returns updated map
Available.erase(key);
return Available;
}
int count(vector<int> sector, int i, unordered_map<int, int> Available, int maxsum) {
if (i == 0) { // all 16 sectors are filled. validate.
if (sector[sector.size() - 2] + sector[sector.size() - 1] + sector[0] <
maxsum) {
if (sector[sector.size() - 1] + sector[0] + sector[1] < maxsum) {
return 1;
} else {
return 0;
}
}
}
int sum = 0;
for (auto k : Available) {
if (i == 1) {
sector[i] = k.first;
sum += count(sector, i + 1, UpdatedMap(Available, k.first), maxsum);
} else {
if (sector[i - 2] + sector[i - 1] + k.first <
maxsum) { // sum of last two sectors and current sector must be
// <27
sector[i] = k.first;
sum += count(sector, (i + 1) % sector.size(),
UpdatedMap(Available, k.first), maxsum);
}
}
}
return sum;
}
int main() {
int k = 16; // k sectors and [1,k] numbers
unordered_map<int, int> Available; // only the key is being used. deletion
// is easy with unordered map.
vector<int> sector;
for (int i = 1; i <= k; i++) {
Available[i] = 1;
sector.push_back(0);
}
sector[0] = 1; // fixed pivot
Available.erase(1);
// fill sectors [1, k-1] with numbers [2, k]
cout << count(sector, 1, Available, 27) << "\n";
cout << "Done! \n";
}
With smaller values of k
and arbitrarily large values of maxsum
and the program outputs (k-1)!
as expected. However when k=16, irrespective of the value of maxsum, the program becomes too slow.
Is there a better way to do this? I'm guessing maybe there's some kind of pattern which I missed.