C, 2765 (optimum)
Düzenle
Şimdi hepsi tek bir C dosyasında. Bu sadece en uygun çözümleri bulur. Hepsinde 15 harfli 6 kelime ve 8 harfli 1 harf ve iki boşluktan oluşan 10 harfli bir kelime bulunmalıdır. Bunun için sözlüğün sadece bir kısmını yüklemem gerekiyor ve boşlukları olan 15 harfli kelime aramam gerekmiyor. Kod basit bir derinlik-ilk aramadır.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct w {
struct lc { uint64_t hi,lo; } lc;
char w[16];
} w15[6000], w10[40000];
int n15,n10;
struct lc pool = { 0x12122464612, 0x8624119232c4229 };
int pts[27] = {0,1,3,3,2,1,4,2,4,1,8,5,1,3,1,1,3,10,1,1,1,1,4,4,8,4,10};
int f[27],fs[26], w15c[27],w15l[27][6000];
int count(struct lc a, int l) { return (l < 16 ? a.lo << 4 : a.hi) >> 4*(l&15) & 15; }
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
int matches(struct lc all, struct lc a) { return matches_val(all.hi,a.hi) && matches_val(all.lo,a.lo); }
int picks[10];
void try(struct lc cur, int used, int level) {
int c, i, must;
if (level == 6) {
for (i = 0; i<27; i++) if (count(cur, i) && pts[i]>1) return;
for (i = 0; i < n10; i++) if(!(used & (1 << (w10[i].w[0] & 31))) && matches(w10[i].lc, cur)) {
for (c = 0; c<level; c++) printf("%s ",w15[picks[c]].w);
printf("%s\n",w10[i].w);
}
return;
}
for (i = 0; i < 26;i++) if (count(cur,fs[i])) break;
must = fs[i];
for (c = 0; c < w15c[must]; c++) { i = w15l[must][c]; if(!(used & (1 << (w15[i].w[0] & 31))) && matches(cur, w15[i].lc)) {
struct lc b = { cur.hi - w15[i].lc.hi, cur.lo - w15[i].lc.lo };
picks[level] = i;
try(b, used + (1 << (w15[i].w[0] & 31)), level+1);
}}
}
int cmpfs(int *a, int *b){return f[*a]-f[*b];}
void ins(struct w*w, char *s, int c) {
int i;
strcpy(w->w,s);
for (;*s;s++)
if (*s&16) w->lc.hi += 1ll << 4*(*s&15); else w->lc.lo += 1ll << 4*(*s&15) - 4;
if (c) for (i = 0; i < 27;i++) if (count(w->lc,i)) f[i]++, w15l[i][w15c[i]++] = w-w15;
}
int main() {
int i;
char s[20];
while(scanf("%s ",s)>0) {
if (strlen(s) == 15) ins(w15 + n15++,s,1);
if (strlen(s) == 10) ins(w10 + n10++,s,0);
}
for (i = 0; i < 26;i++) fs[i] = i+1;
qsort(fs, 26, sizeof(int), cmpfs);
try(pool, 0, 0);
}
Kullanımı:
$time ./scrab <sowpods.txt
cc -O3 scrab.c -o scrab
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LAURUSTINE
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LUXURIATED
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LUXURIATES
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS ULTRAQUIET
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS UTRICULATE
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LAURUSTINE
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LUXURIATED
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LUXURIATES
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS ULTRAQUIET
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS UTRICULATE
OVERADJUSTMENTS QUODLIBETARIANS ACKNOWLEDGEABLY WEATHERPROOFING EXEMPLIFICATIVE HYDROGENIZATION RUBIACEOUS
OVERADJUSTMENTS QUODLIBETARIANS WEATHERPROOFING ACKNOWLEDGEABLY EXEMPLIFICATIVE HYDROGENIZATION RUBIACEOUS
real 0m1.754s
user 0m1.753s
sys 0m0.000s
Her çözümün iki kez yazdırıldığına dikkat edin, çünkü 15 harfli 'W' kelimesi eklenirken 2 'W' kutucuğu olduğu için 2 sipariş oluşturulur.
Nokta dökümü ile bulunan ilk çözüm:
JUXTAPOSITIONAL 465
DEMISEMIQUAVERS 480
ACKNOWLEDGEABLY 465
WEATHERPROOFING 405
CONVEYORIZATION 480
FEATHERBEDDINGS 390
LAURUSTINE (LAURU?TI?E) 80
no tiles left
Düzenle: açıklama
Tüm alanın aranmasını mümkün kılan nedir? Yeni bir kelime eklerken, en nadir harfleri olan kelimeleri dikkate alırım. Bu harfin yine de bir kelimede olması gerekiyor (ve 15 harfli bir kelime çünkü bu 1 değerlikli olmayan bir mektup olacak, ancak bunu kontrol etmiyorum). Bu yüzden J, Q, W, W, X, Z
etrafta sayan kelimeler içeren kelimelerle başlıyorum 50, 100, 100, 100, 200, 500
. Daha düşük seviyelerde daha fazla kesim elde ederim, çünkü bazı kelimeler harf eksikliği nedeniyle ortadan kaldırılıyor. Her düzeyde arama ağacının genişliği:
0: 1
1: 49
2: 3046
3: 102560
4: 724040
5: 803959
6: 3469
Tabii ki, optimal olmayan çözümleri (15 harfli kelime veya daha kısa kelime içeren boşluklar) kontrol etmeyerek çok sayıda kesim elde edilir. Bu nedenle, bu sözlükle 2765 çözümünün elde edilebileceği şanslı (ancak yakındı, 15 harfli kelimeden sadece 2 kombinasyon makul bir artık veriyor). Öte yandan, kalan 10 harfin hepsinin 1 değerli olmadığı daha düşük puanlama kombinasyonları bulmak için kodu değiştirmek kolaydır, ancak bunun en uygun çözüm olacağını kanıtlamak daha zor olacaktır.
Ayrıca kod, klasik erken optimizasyon durumunu gösterir. Bu matches
işlev sürümü kodu yalnızca% 30 daha yavaş hale getirir:
int matches(struct lc all, struct lc a) {
int i;
for (i = 1; i < 27; i++) if (count(a, i) > count(all, i)) return 0;
return 1;
}
Hatta biraz sihirli paralel karşılaştırmayı orijinal kodumdan bile daha kısa nasıl yapacağımı anladım (en yüksek kırıntı bu durumda kullanılamaz, ancak 32 problemden sadece 26'sına ihtiyacım olduğu için bu bir sorun değil):
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
Ancak sıfır avantaj sağlar.
Düzenle
Yukarıdaki açıklamayı yazarak, çoğu zaman matches
işlevde olmayan belirli bir harf içeren sözcüklerin listesini taramak için harcandığını fark ettim . Listeleri önceden hesaplamak 10 kat hız verdi.