De algoritmes beschreven:
Dank! Ik ben inmiddels begonnen met een ebook over Haskell, leerzaam dit.
Ik denk dat oplossing 3 en 4 net zoiets zijn als jij gedaan hebt. Volgens mij hoef je geen deelrijen bij te houden. De hoogtes die voor een bepaald aantal hits het laagst zijn is voldoende.
Ah ik zie 't, slim. Je kunt dan niet meer de (of een) optimale deelrij genereren, maar dat hoeft ook niet (alleen het aantal was gevraagd) dus dat scheelt alleen maar tijd, fraai ja!
Dan heb je mij verkeerd begrepen. Hij rekent n=1 t/m n=10 in 3 seconden uit.
Maar die eerste 9 krijg je er gratis bij he
Ik heb om het snelheidsverschil eens te bekijken ook een geoptimaliseerde variant in C++ gemaakt. Is TIG keer zo lang, maar ook tig keer zo snel:
Verborgen inhoudCode: Selecteer alles
// (windows troep zonodig weghalen voor ander platform)
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
//------------------------------------------------------------------------------
typedef unsigned __int64 Polyonimo;
typedef unsigned __int64 PolyonimoBits;
typedef __int64 PolyonimoDelta;
#include <vector>
typedef std::vector<Polyonimo> PolyonimoList;
static const PolyonimoBits bit = 1;
//------------------------------------------------------------------------------
PolyonimoDelta inline pMax( const PolyonimoDelta &a, const PolyonimoDelta &b )
{
// max(a,b) zonder branching (if)
const PolyonimoDelta c = (a-b)>>(sizeof(a)*8-1);
return (b&c)|(a&~c);
}
//------------------------------------------------------------------------------
static Polyonimo CreatePolyonimo( unsigned w, unsigned h, PolyonimoBits c )
{
// normaliseer
unsigned int s = w*h;
PolyonimoDelta m = (int)(h-w);
if (!m)
{
// vierkant: vergelijk vier orientaties
unsigned int p = (s-1);
unsigned int q = s-w;
unsigned int r = w-1;
PolyonimoBits zz = bit<<p;
PolyonimoBits x1,x2,y1,y2;
x1 = x2 = y1 = y2 = 0;
unsigned int zx,zy,z;
for (zx=zy=z=0; z<s; z++)
{
if ((c>>z)&1) x1 |= zz;
if ((c>>p)&1) x2 |= zz;
if ((c>>(q+zy-zx))&1) y1 |= zz;
if ((c>>(r+zx-zy))&1) y2 |= zz;
m = pMax(y1,y2)-pMax(x1,x2);
if (m) break;
if ((zx+=w)>=s) { zx=0; zy++; }
p--;
zz >>= 1;
}
}
if (m>0) // roteer 90 indien nodig
{
PolyonimoBits c2=0;
unsigned int x,y,z=0;
for (y=h-1;;)
{
for (x=0; x<s; x+=h)
{
if ((c>>(z++))&1) c2 |= bit<<(x+y);
}
if (!y) break;
y--;
}
c = c2;
z = w;
w = h;
h = z;
}
//roteer 180 indien nodig
PolyonimoBits i = 1;
PolyonimoBits j = bit<<(--s);
for (bool r=0;;)
{
PolyonimoBits ci = c & i;
PolyonimoBits cj = c & j;
if (ci || cj)
{
if (!r) { if (!cj) break; if (!ci) r = true; }
if (r) c = (c & ~(i|j)) | (ci<<s) | (cj>>s);
}
i += i;
j >>= 1;
if (s<2) break;
s -= 2;
}
return c | (((PolyonimoBits)((w<<4)|h))<<56);
}
//------------------------------------------------------------------------------
static void AddToList( PolyonimoList *list, const Polyonimo &p )
{
// voeg toe indien nog niet in lijst
unsigned int n = (unsigned int) list->size();
unsigned int b = 1;
while (b<n) b+=b;
unsigned int i;
for (i=0; b; b>>=1 ) // (binary search)
{
unsigned int j = i+b;
if (j>n) continue;
PolyonimoDelta d = p - (*list)[j-1];
if (!d) return; // zat al in lijst
if (d>0) i = j;
}
list->insert(list->begin()+i,p);
}
//------------------------------------------------------------------------------
static void AddExtensions( const Polyonimo &p, PolyonimoList *dest )
{
// voeg alle uitbreidingen toe aan lijst
unsigned int w = (unsigned int) (p>>56);
unsigned int h = w & 0xf;
w >>= 4;
PolyonimoBits c = p & 0xffffffffffffff;
unsigned int x,y;
unsigned int w1 = w-1;
unsigned int h1 = h-1;
PolyonimoBits mz = 1;
for (y=0; y<h; y++) // voeg binnenin blokje toe
{
PolyonimoBits bx = y ? (mz>>w) : 0;
if (y<h1) bx |= mz<<w;
for (x=0; x<w; x++)
{
if (!(c&mz)) // dit vakje nog niet bezet?
{
// check buren
PolyonimoBits b = bx<<x;
if (x) b |= mz>>1;
if (x<w1) b |= mz<<1;
if (c & b) AddToList(dest,CreatePolyonimo(w,h,c|mz));
}
mz += mz;
}
}
for (unsigned int i=0; i<2; i++)
{
// twee keer links en rechts blokjes toevoegen
if (i) // tweede keer geroteerd (nu eigenlijk boven & onder)
{
unsigned int z,q = w*h;
PolyonimoBits c2 = 0;
y = h1;
for(z=0;;)
{
for (x=0; x<q; x+=h)
{
if ((c>>(z++))&1) c2 |= bit<<(x+y);
}
if (!y) break;
y--;
}
c = c2;
z = w;
w = h;
h = z;
}
// voeg lege kolom toe
PolyonimoBits r = (bit<<w)-1;
PolyonimoBits c2 = 0;
for (y=0; y<h;)
{
c2 |= (c&r) << (++y);
r <<= w;
}
// voeg links/rechts blokjes toe
w1 = w+1;
PolyonimoBits k1 = 2;
PolyonimoBits k2 = bit<<w;
for (y=0;;)
{
if (c2 & k1) AddToList(dest,CreatePolyonimo(w1,h,c2|(k1>>1)));
if (c2 & k2) AddToList(dest,CreatePolyonimo(w1,h,(c2>>1)|k2));
if ((++y)>=h) break;
k1 <<= w1;
k2 <<= w1;
}
}
}
//------------------------------------------------------------------------------
static unsigned int GetPolyonimos( unsigned int n, PolyonimoList *dest )
{
if (n==1) AddToList(dest,CreatePolyonimo(1,1,1));
else
{
PolyonimoList prev;
unsigned int np = GetPolyonimos(n-1,&prev);
for (size_t i=0; i<np; i++) AddExtensions(prev[i],dest);
}
return (unsigned int) dest->size();
}
//------------------------------------------------------------------------------
static unsigned int CountPolyonimos( unsigned int n )
{
PolyonimoList dummy;
return GetPolyonimos(n,&dummy);
}
//------------------------------------------------------------------------------
#pragma comment (lib,"winmm.lib")
static int milliTime() { return timeGetTime(); }
//------------------------------------------------------------------------------
int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdLine, int nCmdShow)
{
int k = 12;
int t = milliTime();
int n = CountPolyonimos(k);
t = milliTime()-t;
char s[100];
sprintf(s,"%d: %d (%d msec)",k,n,t);
MessageBoxA(NULL,s,"",0);
return 0;
}
(pas op, hele lap code)
Deze volgt hetzelfde principe (iedere polyomino van orde n op alle mogelijke manieren met 1 blokje uitbreiden, normaliseren, en aan lijst toevoegen als hij er nog niet in stond) maar ik sla de polyomino's nu binair op (als een 64-bit int). Dat komt de snelheid bepaald ten goede: n=1 t/m n=11 duurt ongeveer 0.1 sec, t/m 12 duurt nog geen 1 sec, en t/m 13 (476270 stuks) duurt nog geen 10 sec.
In theory, there's no difference between theory and practice. In practice, there is.