มีหลายวิธีในการแก้ไขปัญหานี้ รูปแบบของข้อมูลเชิงภาพแสดงให้เห็นถึงวิธีการเชิงภาพเชิงภาพ ในการทบทวนวิธีการเหล่านั้นการกำหนดปัญหาในฐานะโปรแกรมเลขจำนวนเต็มแบบไบนารีเชิงเส้นนั้นดูมีแนวโน้มเพราะมันเป็นสิ่งที่มีความสำคัญอย่างมากในการวิเคราะห์การเลือกไซต์ GIS จำนวนมากและสามารถปรับให้เข้ากับพวกเขาได้
ในสูตรนี้เราจะระบุตำแหน่งและทิศทางที่เป็นไปได้ทั้งหมดของรูปหลายเหลี่ยมที่เติมซึ่งฉันจะเรียกว่า "ไทล์" การเชื่อมโยงกับแต่ละไทล์เป็นการวัดความดีของมัน มีวัตถุประสงค์เพื่อค้นหาชุดของแผ่นกระเบื้องที่ไม่ทับซ้อนกันซึ่งมีความดีรวมมากที่สุดเท่าที่จะเป็นไปได้ ที่นี่เราสามารถนำคุณความดีของแต่ละกระเบื้องมาเป็นพื้นที่ครอบคลุม (ในสภาพแวดล้อมการตัดสินใจที่มีข้อมูลจำนวนมากและมีความซับซ้อนเราอาจกำลังคำนวณความดีเนื่องจากการรวมคุณสมบัติของเซลล์ที่รวมอยู่ในแต่ละไทล์คุณสมบัติอาจเกี่ยวข้องกับการมองเห็นความใกล้ชิดกับสิ่งอื่น ๆ เป็นต้น)
ข้อ จำกัด ของปัญหานี้ก็คือว่าไม่มีสองไทล์ภายในโซลูชันอาจทับซ้อนกัน
นี้สามารถกรอบเล็ก ๆ น้อย ๆ ขึ้น abstractly,ในทางที่เอื้อต่อการคำนวณที่มีประสิทธิภาพโดยแจงเซลล์ในรูปหลายเหลี่ยมที่จะเต็มไป (ที่ "ภูมิภาค") 1, 2, ... , M การจัดวางตำแหน่งใด ๆ สามารถเข้ารหัสด้วยเวกเตอร์ตัวบ่งชี้ของศูนย์และรายการปล่อยให้รายการที่สอดคล้องกับเซลล์ที่ครอบคลุมโดยกระเบื้องและศูนย์ที่อื่น ๆ ในการเข้ารหัสนี้ข้อมูลทั้งหมดที่จำเป็นเกี่ยวกับคอลเลกชันของกระเบื้องสามารถพบได้โดยข้อสรุปเวกเตอร์ตัวบ่งชี้ของพวกเขา (องค์ประกอบโดยองค์ประกอบตามปกติ): ผลรวมจะไม่ใช่ศูนย์ตรงที่อย่างน้อยหนึ่งครอบคลุมกระเบื้องเซลล์และผลรวมจะมากขึ้น มากกว่าหนึ่งที่ใดก็ได้สองแผ่นหรือมากกว่านั้นทับซ้อนกัน (ยอดรวมนับจำนวนการเหลื่อมกันอย่างมีประสิทธิภาพ)
หนึ่งในสิ่งที่เป็นนามธรรมเล็ก ๆ น้อย ๆ : ชุดของตำแหน่งกระเบื้องที่เป็นไปได้ของตัวเองสามารถแจกแจงพูด 1, 2, ... , N การเลือกชุดตำแหน่งใด ๆ ของกระเบื้องนั้นสอดคล้องกับเวกเตอร์ตัวบ่งชี้ที่ตำแหน่งนั้นจะกำหนดให้วางแผ่น
นี่คือตัวอย่างเล็ก ๆ ในการแก้ไขปัญหาความคิด มันมาพร้อมกับรหัสMathematica ที่ใช้ในการคำนวณเพื่อให้ปัญหาการเขียนโปรแกรม (หรือขาดมัน) สามารถเห็นได้
อันดับแรกเราแสดงพื้นที่ที่จะปูกระเบื้อง:
region = {{0, 0, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
ถ้าเรานับจำนวนเซลล์จากซ้ายไปขวาเริ่มต้นที่ด้านบนเวกเตอร์ตัวบ่งชี้สำหรับภูมิภาคมี 16 รายการ:
Flatten[region]
{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
ลองใช้ไทล์ต่อไปนี้พร้อมกับการหมุนทั้งหมดด้วยทวีคูณ 90 องศา:
tileSet = {{{1, 1}, {1, 0}}};
รหัสเพื่อสร้างการหมุน (และการสะท้อน):
apply[s_List, alpha] := Reverse /@ s;
apply[s_List, beta] := Transpose[s];
apply[s_List, g_List] := Fold[apply, s, g];
group = FoldList[Append, {}, Riffle[ConstantArray[alpha, 4], beta]];
tiles = Union[Flatten[Outer[apply[#1, #2] &, tileSet, group, 1], 1]];
(การคำนวณที่ค่อนข้างทึบนี้อธิบายไว้ในคำตอบที่/math//a/159159ซึ่งแสดงให้เห็นว่ามันสร้างการหมุนและการสะท้อนของกระเบื้องที่เป็นไปได้ทั้งหมดแล้วลบผลลัพธ์ที่ซ้ำกันออก)
สมมติว่าเราต้องวางกระเบื้องดังที่แสดงไว้ที่นี่:
เซลล์ 3, 6 และ 7 ครอบคลุมอยู่ในตำแหน่งนี้ ที่ถูกกำหนดโดยตัวบ่งชี้เวกเตอร์
{0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
ถ้าเราเลื่อนไทล์นี้หนึ่งคอลัมน์ไปทางขวาเวกเตอร์ตัวบ่งชี้นั้นจะเป็นแทน
{0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
การรวมกันของความพยายามที่จะวางกระเบื้องที่ตำแหน่งทั้งสองเหล่านี้พร้อมกันจะถูกกำหนดโดยผลรวมของตัวบ่งชี้เหล่านี้
{0, 0, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
2 ในตำแหน่งที่เจ็ดแสดงการเหลื่อมกันเหล่านี้ในเซลล์เดียว (แถวที่สองลงมาคอลัมน์ที่สามจากด้านซ้าย) เนื่องจากเราไม่ต้องการเหลื่อมกันเราจึงต้องการให้ผลรวมของเวกเตอร์ในโซลูชันที่ถูกต้องใด ๆ ต้องไม่มีรายการเกิน 1
ปรากฎว่าสำหรับปัญหานี้ 29 ชุดของการวางแนวและตำแหน่งเป็นไปได้สำหรับกระเบื้อง (สิ่งนี้ถูกค้นพบด้วยการเขียนโปรแกรมที่เกี่ยวข้องกับการค้นหาแบบละเอียด) เราสามารถอธิบายความเป็นไปได้ทั้งหมด 29 ข้อโดยการวาดตัวชี้วัดเป็นเวกเตอร์คอลัมน์ (การใช้คอลัมน์แทนที่จะเป็นแบบดั้งเดิม) นี่คือรูปภาพของอาร์เรย์ผลลัพธ์ซึ่งจะมี 16 แถว (หนึ่งคอลัมน์สำหรับแต่ละเซลล์ที่เป็นไปได้ในสี่เหลี่ยมผืนผ้า) และ 29 คอลัมน์:
makeAllTiles[tile_, {n_Integer, m_Integer}] :=
With[{ m0 = Length[tile], n0 = Length[First[tile]]},
Flatten[
Table[ArrayPad[tile, {{i, m - m0 - i}, {j, n - n0 - j}}], {i, 0, m - m0}, {j, 0, n - n0}], 1]];
allTiles = Flatten[ParallelMap[makeAllTiles[#, ImageDimensions[regionImage]] & , tiles], 1];
allTiles = Parallelize[
Select[allTiles, (regionVector . Flatten[#]) >= (Plus @@ (Flatten[#])) &]];
options = Transpose[Flatten /@ allTiles];
(เวกเตอร์ตัวบ่งชี้ที่สองก่อนหน้านี้ปรากฏเป็นสองคอลัมน์แรกทางด้านซ้าย) เครื่องอ่านแบบตาเดียวอาจสังเกตเห็นโอกาสหลายอย่างสำหรับการประมวลผลแบบขนาน: การคำนวณเหล่านี้อาจใช้เวลาสองสามวินาที
ทั้งหมดที่กล่าวมาสามารถปรับปรุงใหม่ได้อย่างกะทัดรัดโดยใช้สัญกรณ์เมทริกซ์:
Fคืออาร์เรย์ของตัวเลือกนี้ด้วยแถวMและคอลัมน์N
Xเป็นตัวบ่งชี้ของชุดของตำแหน่งกระเบื้องที่มีความยาวN
bคือN -vector ของอันใดอันหนึ่ง
Rคือตัวบ่งชี้สำหรับภูมิภาค มันเป็นM -vector
"ความดี" ทั้งหมดที่เกี่ยวข้องกับโซลูชันXใด ๆ ที่เป็นไปได้เท่ากับRFXเนื่องจากFXเป็นตัวบ่งชี้ของเซลล์ที่ครอบคลุมโดยXและผลิตภัณฑ์ที่มีR จะรวมค่าเหล่านี้ (เราสามารถให้น้ำหนักR ได้หากเราต้องการวิธีแก้ปัญหาเพื่อช่วยเหลือหรือหลีกเลี่ยงบางพื้นที่ในภูมิภาค) นี่คือการขยายให้ใหญ่สุด เพราะเราสามารถเขียนมันเป็น ( RF ) Xมันเป็นฟังก์ชันเชิงเส้นของX : นี่คือสิ่งสำคัญ (ในรหัสด้านล่างตัวแปรc
มีRF )
ข้อ จำกัด อยู่ที่ว่า
องค์ประกอบทั้งหมดของXต้องไม่เป็นลบ
องค์ประกอบทั้งหมดของXจะต้องน้อยกว่า 1 (ซึ่งเป็นรายการที่สอดคล้องกันในb );
องค์ประกอบทั้งหมดของXจะต้องเป็นส่วนประกอบสำคัญ
ข้อ จำกัด (1) และ (2) ทำให้โปรแกรมเชิงเส้นตรงในขณะที่ข้อกำหนดที่สามเปลี่ยนเป็นโปรแกรมเชิงเส้นจำนวนเต็ม
มีแพคเกจมากมายสำหรับการแก้โปรแกรมเชิงเส้นจำนวนเต็มที่แสดงในรูปแบบนี้ พวกเขามีความสามารถในการจัดการค่าของMและNเป็นหมื่นหรือแม้กระทั่งนับแสน นั่นอาจดีพอสำหรับแอปพลิเคชันในโลกแห่งความจริง
ในฐานะภาพประกอบแรกของฉันฉันคำนวณวิธีแก้ปัญหาสำหรับตัวอย่างก่อนหน้านี้โดยใช้คำสั่งของMathematica 8 LinearProgramming
(สิ่งนี้จะลดฟังก์ชั่นเชิงเส้นตรงให้เล็กที่สุดทำให้การย่อขนาดกลายเป็นขนาดสูงสุดได้อย่างง่ายดายโดยการลบฟังก์ชันวัตถุประสงค์) มันส่งคืนโซลูชัน (เป็นรายการของกระเบื้องและตำแหน่ง) ใน 0.011 วินาที:
b = ConstantArray[-1, Length[options]];
c = -Flatten[region].options;
lu = ConstantArray[{0, 1}, Length[First[options]]];
x = LinearProgramming[c, -options, b, lu, Integers, Tolerance -> 0.05];
If[! ListQ[x] || Max[options.x] > 1, x = {}];
solution = allTiles[[Select[x Range[Length[x]], # > 0 &]]];
เซลล์สีเทาไม่ได้อยู่ในพื้นที่เลย สารละลายนี้ไม่ได้ครอบคลุมเซลล์สีขาว
คุณสามารถออกกำลังกาย (ด้วยมือ) อีกหลายอย่างที่ดีเท่านี้ - แต่คุณไม่สามารถหาสิ่งที่ดีกว่า นั่นเป็นข้อ จำกัด ที่เป็นไปได้ของวิธีนี้: มันให้ทางออกที่ดีที่สุดวิธีหนึ่งแก่คุณแม้ว่าจะมีมากกว่าหนึ่ง (มีวิธีแก้ไขปัญหาบางอย่าง: หากเราจัดลำดับคอลัมน์Xใหม่ปัญหายังคงไม่เปลี่ยนแปลง แต่ซอฟต์แวร์มักจะเลือกวิธีการแก้ปัญหาที่แตกต่างกันออกไปอย่างไรก็ตามพฤติกรรมนี้ไม่สามารถคาดเดาได้)
เป็นภาพประกอบที่สองเพื่อให้สมจริงยิ่งขึ้นลองพิจารณาพื้นที่ในคำถาม ด้วยการนำเข้าภาพและทำการสุ่มภาพใหม่อีกครั้งฉันแสดงภาพด้วยกริด 69 x 81 ตาราง:
ภูมิภาคประกอบด้วยเซลล์ 2156 ของตารางนี้
เพื่อทำให้สิ่งต่าง ๆ น่าสนใจและเพื่อแสดงให้เห็นถึงความเป็นสากลของการตั้งค่าการเขียนโปรแกรมเชิงเส้นเราพยายามที่จะครอบคลุมภูมิภาคนี้ให้มากที่สุดด้วยสี่เหลี่ยมสองชนิด:
หนึ่งคือ 17 โดย 9 (153 เซลล์) และอีกอันคือ 15 โดย 11 (165 เซลล์) เราอาจชอบที่จะใช้อันที่สองเพราะมันมีขนาดใหญ่กว่า แต่อันแรกนั้นน่าจะเหมาะกว่าและน่าอยู่กว่า มาดูกัน!
ตอนนี้โปรแกรมเกี่ยวข้องกับตำแหน่งที่เป็นไปได้ของN = 5589 มันค่อนข้างใหญ่! หลังจากการคำนวณ 6.3 วินาทีMathematicaก็เกิดปัญหากับกระเบื้องสิบแผ่นนี้:
เนื่องจากความหย่อนบาง ( .egเราสามารถเลื่อนไทล์ซ้ายล่างสูงสุดสี่คอลัมน์ไปทางซ้าย) จึงมีวิธีแก้ปัญหาอื่นที่แตกต่างจากอันนี้เล็กน้อย