C ++ 11, 28'ler
Bu, satırlara dayalı dinamik bir programlama yaklaşımı da kullanır. Benim için 13 numaralı argümanı çalıştırmak 28 saniye sürdü. En sevdiğim hile, next
bir maskeyi ve satırda 3'ü olmayan kuralı tatmin eden sözlükbilimsel olarak sıradaki sıra düzenlemesini bulmak için biraz dayak kullanan işlevdir.
Talimatlar
- SEH ve Posix dişleri ile en yeni MinGW-w64'ü kurun
- Programı şununla derleyin:
g++ -std=c++11 -march=native -O3 <filename>.cpp -o <executable name>
- Şununla koş:
<executable name> <n>
#include <vector>
#include <stddef.h>
#include <iostream>
#include <string>
#ifdef _MSC_VER
#include <intrin.h>
#define popcount32 _mm_popcnt_u32
#else
#define popcount32 __builtin_popcount
#endif
using std::vector;
using row = uint32_t;
using xcount = uint8_t;
uint16_t rev16(uint16_t x) { // slow
static const uint8_t revbyte[] {0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255};
return uint16_t(revbyte[x >> 8]) | uint16_t(revbyte[x & 0xFF]) << 8;
}
// returns the next number after r that does not overlap the mask or have three 1's in a row
row next(row r, uint32_t m) {
m |= r >> 1 & r >> 2;
uint32_t x = (r | m) + 1;
uint32_t carry = x & -x;
return (r | carry) & -carry;
}
template<typename T, typename U> void maxequals(T& m, U v) {
if (v > m)
m = v;
}
struct tictac {
const int n;
vector<row> rows;
size_t nonpal, nrows_c;
vector<int> irow;
vector<row> revrows;
tictac(int n) : n(n) { }
row reverse(row r) {
return rev16(r) >> (16 - n);
}
vector<int> sols_1row() {
vector<int> v(1 << n);
for (uint32_t m = 0; !(m >> n); m++) {
auto m2 = m;
int n0 = 0;
int score = 0;
for (int i = n; i--; m2 >>= 1) {
if (m2 & 1) {
n0 = 0;
} else {
if (++n0 % 3)
score++;
}
}
v[m] = score;
}
return v;
}
void gen_rows() {
vector<row> pals;
for (row r = 0; !(r >> n); r = next(r, 0)) {
row rrev = reverse(r);
if (r < rrev) {
rows.push_back(r);
} else if (r == rrev) {
pals.push_back(r);
}
}
nonpal = rows.size();
for (row r : pals) {
rows.push_back(r);
}
nrows_c = rows.size();
for (int i = 0; i < nonpal; i++) {
rows.push_back(reverse(rows[i]));
}
irow.resize(1 << n);
for (int i = 0; i < rows.size(); i++) {
irow[rows[i]] = i;
}
revrows.resize(1 << n);
for (row r = 0; !(r >> n); r++) {
revrows[r] = reverse(r);
}
}
// find banned locations for 1's given 2 above rows
uint32_t mask(row a, row b) {
return ((a & b) | (a >> 1 & b) >> 1 | (a << 1 & b) << 1) /*& ((1 << n) - 1)*/;
}
int calc() {
if (n < 3) {
return n * n;
}
gen_rows();
int tdim = n < 5 ? n : (n + 3) / 2;
size_t nrows = rows.size();
xcount* t = new xcount[2 * nrows * nrows_c]{};
#define tb(nr, i, j) t[nrows * (nrows_c * ((nr) & 1) + (i)) + (j)]
// find optimal solutions given 2 rows for n x k grids where 3 <= k <= ceil(n/2) + 1
{
auto s1 = sols_1row();
for (int i = 0; i < nrows_c; i++) {
row a = rows[i];
for (int j = 0; j < nrows; j++) {
row b = rows[j];
uint32_t m = mask(b, a) & ~(1 << n);
tb(3, i, j) = s1[m] + popcount32(a << 16 | b);
}
}
}
for (int r = 4; r <= tdim; r++) {
for (int i = 0; i < nrows_c; i++) {
row a = rows[i];
for (int j = 0; j < nrows; j++) {
row b = rows[j];
bool rev = j >= nrows_c;
auto cj = rev ? j - nrows_c : j;
uint32_t m = mask(a, b);
for (row c = 0; !(c >> n); c = next(c, m)) {
row cc = rev ? revrows[c] : c;
int count = tb(r - 1, i, j) + popcount32(c);
maxequals(tb(r, cj, irow[cc]), count);
}
}
}
}
int ans = 0;
if (tdim == n) { // small sizes
for (int i = 0; i < nrows_c; i++) {
for (int j = 0; j < nrows; j++) {
maxequals(ans, tb(n, i, j));
}
}
} else {
int tdim2 = n + 2 - tdim;
// get final answer by joining two halves' solutions down the middle
for (int i = 0; i < nrows_c; i++) {
int apc = popcount32(rows[i]);
for (int j = 0; j < nrows; j++) {
row b = rows[j];
int top = tb(tdim2, i, j);
int bottom = j < nrows_c ? tb(tdim, j, i) : tb(tdim, j - nrows_c, i < nonpal ? i + nrows_c : i);
maxequals(ans, top + bottom - apc - popcount32(b));
}
}
}
delete[] t;
return ans;
}
};
int main(int argc, char** argv) {
int n;
if (argc < 2 || (n = std::stoi(argv[1])) < 0 || n > 16) {
return 1;
}
std::cout << tictac{ n }.calc() << '\n';
return 0;
}