C, 2765 (เหมาะสมที่สุด)
แก้ไข
ตอนนี้ทั้งหมดอยู่ในไฟล์ C ไฟล์เดียว นี่เป็นเพียงการหาทางออกที่ดีที่สุดทั้งหมด พวกเขาทั้งหมดจะต้องมี 6 คำ 15 ตัวอักษรและคำ 10 ตัวอักษรหนึ่งประกอบด้วย 8 ตัวอักษรของค่า 1 และสองช่องว่าง เพื่อที่ฉันจะต้องโหลดเพียงเศษเสี้ยวของพจนานุกรมและฉันไม่ต้องมองหา 15 คำตัวอักษรด้วยช่องว่าง รหัสคือการค้นหาความลึกแรกอย่างละเอียด
#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);
}
การใช้งาน:
$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
โปรดทราบว่าทุกโซลูชันจะถูกพิมพ์สองครั้งเพราะเมื่อสร้างคำสั่ง 'W' 2 คำ 15 ตัวจะถูกสร้างขึ้นเนื่องจากมีไทล์ 2 'W'
วิธีแก้ปัญหาแรกที่พบเมื่อมีการแยกจุด:
JUXTAPOSITIONAL 465
DEMISEMIQUAVERS 480
ACKNOWLEDGEABLY 465
WEATHERPROOFING 405
CONVEYORIZATION 480
FEATHERBEDDINGS 390
LAURUSTINE (LAURU?TI?E) 80
no tiles left
แก้ไข: คำอธิบาย
อะไรทำให้การค้นหาพื้นที่ทั้งหมดเป็นไปได้ ในขณะที่เพิ่มคำใหม่ฉันเพียงคำนึงถึงคำที่มีตัวอักษรที่เหลือที่หายาก จดหมายนี้ต้องมีบางคำอยู่แล้ว (และคำ 15 ตัวอักษรเนื่องจากนี่จะเป็นตัวอักษรที่ไม่ใช่ค่า 1 ถึงแม้ว่าฉันจะไม่ตรวจสอบสิ่งนั้น) ดังนั้นผมจึงเริ่มต้นด้วยคำพูดที่มีที่มีการนับจำนวนรอบJ, Q, W, W, X, Z
50, 100, 100, 100, 200, 500
ในระดับที่ต่ำกว่าฉันได้รับการตัดมากขึ้นเพราะคำบางคำถูกกำจัดโดยการขาดตัวอักษร ความกว้างของต้นไม้ค้นหาในแต่ละระดับ:
0: 1
1: 49
2: 3046
3: 102560
4: 724040
5: 803959
6: 3469
แน่นอนว่ามีการตัดยอดมากโดยไม่ตรวจสอบโซลูชันที่ไม่เหมาะสม (ช่องว่างใน 15 ตัวอักษรคำหรือคำที่สั้นกว่า) ดังนั้นจึงเป็นเรื่องที่โชคดีที่ 2,658 คำตอบสามารถทำได้ด้วยพจนานุกรมนี้ (แต่ใกล้เคียงกันมีเพียง 2 คำจากตัวอักษร 15 คำที่ให้คำศัพท์ที่เหลืออยู่) ในทางกลับกันมันง่ายที่จะแก้ไขรหัสเพื่อหาชุดค่าผสมที่ให้คะแนนต่ำกว่าซึ่งไม่ใช่ตัวอักษร 10 ตัวที่เหลือทั้งหมดมีค่า 1 แต่มันยากที่จะพิสูจน์ว่านี่เป็นทางออกที่ดีที่สุด
นอกจากนี้รหัสแสดงกรณีคลาสสิกของการเพิ่มประสิทธิภาพก่อนวัยอันควร matches
ฟังก์ชันรุ่นนี้ทำให้โค้ดช้าลง 30% เท่านั้น:
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;
}
ฉันได้คิดวิธีทำให้การเปรียบเทียบแบบเวทย์มนตร์บิตนั้นสั้นกว่าในรหัสเดิมของฉัน (การตอดที่สูงที่สุดไม่สามารถใช้ในกรณีนี้ แต่นี่ไม่ใช่ปัญหาเนื่องจากฉันต้องการเพียง 26 จาก 32 nibbles):
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
แต่มันให้ประโยชน์เป็นศูนย์
แก้ไข
การเขียนคำอธิบายข้างต้นฉันรู้ว่าใช้เวลาส่วนใหญ่ในการสแกนรายการคำศัพท์สำหรับผู้ที่มีตัวอักษรเฉพาะที่ไม่ได้อยู่ในmatches
ฟังก์ชั่น การคำนวณรายการล่วงหน้าให้การเร่งความเร็ว 10x