C, 2765 (optimal)
Edit
Sekarang semua dalam satu file C. Ini hanya menemukan semua solusi optimal. Mereka semua harus memiliki 6 kata 15 huruf dan satu kata 10 huruf yang terdiri dari 8 huruf bernilai 1 dan dua kosong. Untuk itu saya hanya perlu memuat sebagian kecil dari kamus dan saya tidak perlu mencari 15 kata kata dengan kosong. Kode adalah pencarian mendalam-pertama lengkap sederhana.
#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);
}
Pemakaian:
$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
Perhatikan bahwa setiap solusi dicetak dua kali karena ketika menambahkan 15 huruf 'W' kata 2 pesanan dibuat karena ada 2 ubin 'W'.
Solusi pertama yang ditemukan dengan pemecahan titik:
JUXTAPOSITIONAL 465
DEMISEMIQUAVERS 480
ACKNOWLEDGEABLY 465
WEATHERPROOFING 405
CONVEYORIZATION 480
FEATHERBEDDINGS 390
LAURUSTINE (LAURU?TI?E) 80
no tiles left
Edit: penjelasan
Apa yang memungkinkan pencarian seluruh ruang? Sambil menambahkan kata baru saya hanya memperhitungkan kata-kata akun yang memiliki huruf sisa paling langka. Surat ini harus dalam beberapa kata (dan kata 15 huruf karena ini akan menjadi surat yang tidak bernilai 1, meskipun saya tidak memeriksanya). Jadi saya mulai dengan kata-kata yang mengandung J, Q, W, W, X, Z
yang diperhitungkan 50, 100, 100, 100, 200, 500
. Pada level yang lebih rendah saya mendapatkan lebih banyak cutoff karena beberapa kata dihilangkan oleh kurangnya huruf. Luasnya pohon pencarian di setiap tingkat:
0: 1
1: 49
2: 3046
3: 102560
4: 724040
5: 803959
6: 3469
Tentu saja banyak cutoff diperoleh dengan tidak memeriksa solusi yang tidak optimal (kosong dalam 15 kata kata atau kata-kata pendek). Jadi sangat beruntung bahwa 2765 solusi dapat dicapai dengan kamus ini (tapi sudah dekat, hanya 2 kombinasi dari 15 kata kata memberikan sisa yang masuk akal). Di sisi lain, mudah untuk memodifikasi kode untuk menemukan kombinasi skor yang lebih rendah di mana tidak semua 10 huruf sisanya bernilai 1, meskipun akan lebih sulit untuk membuktikan ini akan menjadi solusi yang optimal.
Juga kode menunjukkan kasus klasik optimasi prematur. Versi matches
fungsi ini membuat kode hanya 30% lebih lambat:
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;
}
Saya bahkan menemukan cara untuk membuat perbandingan paralel bit ajaib lebih pendek daripada di kode asli saya (nibble tertinggi tidak dapat digunakan dalam kasus ini, tetapi ini bukan masalah, karena saya hanya perlu 26 dari 32 nibble):
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
Tapi itu memberi keuntungan nol.
Edit
Menulis penjelasan di atas, saya menyadari bahwa sebagian besar waktu dihabiskan untuk memindai daftar kata-kata untuk mereka yang mengandung huruf tertentu yang tidak ada dalam matches
fungsi. Menghitung daftar di muka memberi kecepatan 10x.