ผมเขียนอัลกอริทึมใน C # ที่พยายามทุกชุดที่เป็นไปได้ของคนเหล่านั้นและNor 3->1
Xor 2->1
Nand 2->1
Decoder 3->8
หลังจากใช้งานมาแล้ว7½ล้านปี 2 ชั่วโมงมันก็คืน42 ค่าเท็จ ฉันเชื่อว่านี่เป็นปัญหาที่ไม่มีคำตอบเนื่องจากอัลกอริทึมนี้ตรวจสอบชุดค่าผสมที่เป็นไปได้ทั้งหมด :)
ฉันถูกขอให้อธิบายมันดังนั้นส่วนต่อไปคือคำอธิบายส่วนต่าง ๆ ของรหัสแต่ละส่วน TL; DR - คุณสามารถข้ามไปที่รหัสด้านล่าง :)
ลองพูดถึงบรรทัดอินพุตพวกมันมีสถานะเป็น 0 หรือ 1 และสำหรับแต่ละอินพุตที่เป็นไปได้ (0 ถึง 15) พวกมันมีค่าต่างกัน:
สำหรับบรรทัดแรกดูเหมือนว่า: 0 1 0 1 0 1 ... ที่สองคือ: 0 0 1 1 0 0 1 1 ... ที่สาม: 0 0 0 0 1 1 1 1 1 .... เช่นไบนารี การนับ ... คุณมีความคิด: หน้า
ดังนั้นฉันจึงสร้างวัตถุที่แสดงถึงแต่ละบรรทัดในแต่ละสถานะของเขา:
class BitLine{
bool[] IsActiveWhenInputIs = new bool[16];
}
อย่างที่มันบอกว่า bitLine.IsActiveWhenInputIs [5] จะคืนค่าว่าบรรทัดนั้นแอ็คทีฟหรือไม่เมื่ออินพุตเป็น 5
นี่คือรหัสที่สร้างบรรทัดอินพุตทั้งหมด:
var bitLineList = new BitLine[6]; // initialize new array of bitLines
for (int i = 0; i < 6; i++) bitLineList [i] = new BitLine(); // initialize each bitLine
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 4; j++)
{
int checker = 1 << j; // check whether the j-th bit is activated in the binary representation of the number.
bitLineList[j].IsActiveWhenInputIs[i] = ((checker & i) != 0); // if it's active, the AND result will be none zero, and so the return value will be true - which is what we need :D
}
}
เราจะสร้างบรรทัดบิต "เสมอจริง" และ "เสมอเท็จ" เช่นกัน - เพื่อให้อินพุต "0" หรืออินพุต "1" คงที่
for (int i = 0; i < 16; i++){
bitLineList[4].IsActiveWhenInputIs[i] = false;
bitLineList[5].IsActiveWhenInputIs[i] = true;
}
ตอนนี้ถ้าคุณสังเกตเห็นสิ่งที่เรากำลังมองหาคือ bitLine ที่เฉพาะเจาะจงหนึ่งอันที่เป็นจริงเมื่ออินพุตคือ 0, 7, 14 ลองเป็นตัวแทนในคลาสของเรา:
var neededBitLine = new BitLine();
for (int i = 0; i < 16; i++){
neededBitLine.IsActiveWhenInputIs[i] = ((i % 7) == 0); // be true for any number that is devideble by 7 (0,7,14)
}
สิ่งนี้ทำให้ง่ายมาก ๆ : สิ่งที่เรากำลังมองหาคือวิธี "ปลอม" สิ่งนี้ต้องการ BitLine จากอินพุตบิตไลน์
ตอนนี้เป็นวิธีที่เราจะไปที่: ทุกครั้งที่เราใช้ตรรกะองค์ประกอบบางอย่างใน bitLines ของเราอย่างเช่นXor
, Nor
, Nand
หรือแม้กระทั่งDecoder
เราเป็นจริงสร้าง bitLine ใหม่ \ s เรารู้ค่าของแต่ละบรรทัดในอินพุตที่เป็นไปได้ตั้งแต่ 0 ถึง 15 ดังนั้นเราจึงสามารถคำนวณค่า bitLine \ s ใหม่ในอินพุตที่เป็นไปได้ทุกตัวเช่นกัน!
Nand Nor และ Xor ตรงไปตรงมาทั้งหมด:
void Xor(BitLine b1, BitLine b2, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = b1.IsActiveWhenInputIs[i] != b2.IsActiveWhenInputIs[i];
}
}
void Nand(BitLine b1, BitLine b2, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] && b2.IsActiveWhenInputIs[i]);
}
}
void Nor(BitLine b1, BitLine b2, BitLine b3, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] || b2.IsActiveWhenInputIs[i] || b3.IsActiveWhenInputIs[i]);
}
}
สำหรับแต่ละอินพุตที่เป็นไปได้มันแสดงให้เห็นว่า BitLine ใหม่จะทำหน้าที่อย่างไร
การจัดการตัวถอดรหัสนั้นยุ่งยากเล็กน้อย แต่ความคิดคือ "ถ้าบิตที่อินพุตแสดงตัวเลข x ในไบนารี่จากนั้นบรรทัดบิตเอาต์พุต x-th จะเป็นจริงในขณะที่คนอื่น ๆ ทั้งหมดจะเป็นเท็จ ฟังก์ชันอันนี้จะได้รับอาร์เรย์ของบิตไลน์และเพิ่ม 8 บิตไลน์ใหม่ให้กับอาร์เรย์
void Decoder(BitLine b1, BitLine b2, BitLine b3, List<BitLine> lines, int listOriginalLength)
{
for (int optionNumber = 0; optionNumber < 8; optionNumber++)
{
for (var i = 0; i < 16; i++)
{
int sum = 0;
if (b1.IsActiveWhenInputIs[i]) sum += 4;
if (b2.IsActiveWhenInputIs[i]) sum += 2;
if (b3.IsActiveWhenInputIs[i]) sum += 1;
lines[listOriginalLength+optionNumber].IsActiveWhenInputIs[i] = (sum == optionNumber);
}
}
}
ตอนนี้เรามีองค์ประกอบพื้นฐานทั้งหมดดังนั้นเรามาพูดถึงอัลกอริทึมกัน:
เราจะทำขั้นตอนวิธีแบบเรียกซ้ำโดยที่ความลึกแต่ละระดับจะพยายามใช้องค์ประกอบอื่น (หรือ \ nand \ xor \ decoder) บนบิตไลน์ที่มีอยู่ในปัจจุบันแล้วตั้งค่าองค์ประกอบให้ใช้ไม่ได้สำหรับความลึกแบบเรียกซ้ำครั้งถัดไป เมื่อใดก็ตามที่เรามาถึงจุดต่ำสุดและเราไม่มีองค์ประกอบที่จะใช้อีกต่อไปเราจะตรวจสอบว่าเรามีบิตไลน์ที่เป็นสิ่งที่เรากำลังมองหาหรือไม่
รหัสนี้จะตรวจสอบในเวลาที่กำหนดว่ากลุ่มของบรรทัดปัจจุบันมีบรรทัดที่เรากำลังมองหา:
bool CheckIfSolutionExist(List<BitLine> lines, int linesLength BitLine neededLine)
{
for(int i = 0; i<linesLength; i++){
if (lines[i].CheckEquals(neededLine))
{
return true;
}
}
return false;
}
นี่คือฟังก์ชั่นที่ใช้ตรวจสอบว่ามีสองบรรทัดเท่ากันหรือไม่:
bool CheckEquals(BitLine other)
{
for (var i = 0; i < 16; i++)
{
if (this.IsActiveWhenInputIs[i] != other.IsActiveWhenInputIs[i])
{
return false;
}
}
return true;
}
ตกลงดังนั้นตอนนี้สำหรับส่วนหลักนี่คืออัลกอริทึมหลัก:
bool Solve(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if ((!nand) && (!nor) && (!xor) && (!decoder))
{
return CheckIfSolutionExist(lines, listLength, neededLine);
}
else
{
if (HandleNand(lines, nand, nor, xor, decoder, neededLine,listLength))
{
return true;
}
if (HandleNor(lines, nand, nor, xor, decoder, neededLine,listLength))
{
return true;
}
if (HandleXor(lines, nand, nor, xor, decoder, neededLine,listLength))
{
return true;
}
if (HandleDecoder(lines, nand, nor, xor, decoder, neededLine,listLength))
{
return true;
}
return false;
}
}
ฟังก์ชันนี้รับรายการของ bitLines ที่มีอยู่ความยาวของรายการบูลีนที่แสดงว่าแต่ละองค์ประกอบนั้นมีอยู่ในปัจจุบัน (xor / หรือ / nand / decoder) และ bitLine ที่เป็นตัวแทนของ bitLine ที่เรากำลังค้นหา
ในแต่ละขั้นตอนจะตรวจสอบว่าเรามีองค์ประกอบอื่น ๆ อีกมากมายที่จะใช้หรือไม่ถ้าไม่ตรวจสอบว่าเราเก็บ bitline ที่ต้องการของเราหรือไม่
หากเรายังคงมีองค์ประกอบมากขึ้นดังนั้นสำหรับแต่ละองค์ประกอบมันจะเรียกใช้ฟังก์ชันที่ควรจัดการกับการสร้าง bitLines ใหม่โดยใช้องค์ประกอบเหล่านั้นและเรียกความลึกที่เกิดขึ้นถัดไปหลังจากนั้น
ฟังก์ชั่นจัดการต่อไปทั้งหมดตรงไปตรงมาพวกเขาสามารถแปลเป็น "เลือก 2 \ 3 จากบิตไลน์ที่มีอยู่และรวมเข้าด้วยกันโดยใช้องค์ประกอบที่เกี่ยวข้องจากนั้นเรียกความลึกครั้งถัดไปของการเรียกซ้ำ องค์ประกอบนี้! "
เหล่านี้คือฟังก์ชั่น:
bool HandleNand(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (nand)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
BitLine.Nand(lines[i], lines[j],lines[listLength]);
if (Solve(lines,listLength+1, false, nor, xor, decoder, neededLine))
{
return true;
}
}
}
}
return false;
}
bool HandleXor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (xor)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
BitLine.Xor(lines[i], lines[j],lines[listLength]);
if (Solve(lines,listLength+1, nand, nor, false, decoder, neededLine))
{
return true;
}
}
}
}
return false;
}
bool HandleNor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (nor)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
for (int k = j; k < listLength; k++)
{
BitLine.Nor(lines[i], lines[j], lines[k],lines[listLength]);
if (Solve(lines,listLength+1, nand, false, xor, decoder, neededLine))
{
return true;
}
}
}
}
}
return false;
}
bool HandleDecoder(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (decoder)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
for (int k = j; k < listLength; k++)
{
BitLine.Decoder(lines[i], lines[j], lines[k],lines,listLength);
if (Solve(lines,listLength+8, nand, nor, xor, false, neededLine))
{
return true;
}
}
}
}
}
return false;
}
และนี่คือมันเราแค่เรียกฟังก์ชั่นนี้กับเส้นที่ต้องการที่เรากำลังมองหาและมันจะตรวจสอบการรวมกันของชิ้นส่วนไฟฟ้าที่เป็นไปได้ทั้งหมดเพื่อตรวจสอบว่าเป็นไปได้หรือไม่ที่จะรวมพวกมันเข้าด้วยกัน เอาต์พุตด้วยค่าที่ต้องการ
* สังเกตว่าฉันใช้รายการเดียวกันตลอดเวลาดังนั้นฉันไม่จำเป็นต้องสร้างอินสแตนซ์ bitline ใหม่ตลอดเวลา ฉันให้บัฟเฟอร์ 200 ด้วยเหตุผลนั้น
นี่เป็นโปรแกรมที่สมบูรณ์:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public class BitLine
{
public bool[] IsActiveWhenInputIs = new bool[16];
public static void Xor(BitLine b1, BitLine b2, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = b1.IsActiveWhenInputIs[i] != b2.IsActiveWhenInputIs[i];
}
}
public static void Nand(BitLine b1, BitLine b2, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] && b2.IsActiveWhenInputIs[i]);
}
}
public static void Nor(BitLine b1, BitLine b2, BitLine b3, BitLine outputBitLine)
{
for (var i = 0; i < 16; i++)
{
outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] || b2.IsActiveWhenInputIs[i] || b3.IsActiveWhenInputIs[i]);
}
}
public static void Decoder(BitLine b1, BitLine b2, BitLine b3, List<BitLine> lines, int listOriginalLength)
{
for (int optionNumber = 0; optionNumber < 8; optionNumber++)
{
for (var i = 0; i < 16; i++)
{
int sum = 0;
if (b1.IsActiveWhenInputIs[i]) sum += 4;
if (b2.IsActiveWhenInputIs[i]) sum += 2;
if (b3.IsActiveWhenInputIs[i]) sum += 1;
lines[listOriginalLength + optionNumber].IsActiveWhenInputIs[i] = (sum == optionNumber);
}
}
}
public bool CheckEquals(BitLine other)
{
for (var i = 0; i < 16; i++)
{
if (this.IsActiveWhenInputIs[i] != other.IsActiveWhenInputIs[i])
{
return false;
}
}
return true;
}
}
public class Solver
{
bool CheckIfSolutionExist(List<BitLine> lines, int linesLength, BitLine neededLine)
{
for (int i = 0; i < linesLength; i++)
{
if (lines[i].CheckEquals(neededLine))
{
return true;
}
}
return false;
}
bool HandleNand(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (nand)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
BitLine.Nand(lines[i], lines[j], lines[listLength]);
if (Solve(lines, listLength + 1, false, nor, xor, decoder, neededLine))
{
return true;
}
}
}
}
return false;
}
bool HandleXor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (xor)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
BitLine.Xor(lines[i], lines[j], lines[listLength]);
if (Solve(lines, listLength + 1, nand, nor, false, decoder, neededLine))
{
return true;
}
}
}
}
return false;
}
bool HandleNor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (nor)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
for (int k = j; k < listLength; k++)
{
BitLine.Nor(lines[i], lines[j], lines[k], lines[listLength]);
if (Solve(lines, listLength + 1, nand, false, xor, decoder, neededLine))
{
return true;
}
}
}
}
}
return false;
}
bool HandleDecoder(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if (decoder)
{
for (int i = 0; i < listLength; i++)
{
for (int j = i; j < listLength; j++)
{
for (int k = j; k < listLength; k++)
{
BitLine.Decoder(lines[i], lines[j], lines[k], lines, listLength);
if (Solve(lines, listLength + 8, nand, nor, xor, false, neededLine))
{
return true;
}
}
}
}
}
return false;
}
public bool Solve(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
if ((!nand) && (!nor) && (!xor) && (!decoder))
{
return CheckIfSolutionExist(lines, listLength, neededLine);
}
else
{
if (HandleNand(lines, listLength, nand, nor, xor, decoder, neededLine))
{
return true;
}
if (HandleNor(lines, listLength, nand, nor, xor, decoder, neededLine))
{
return true;
}
if (HandleXor(lines, listLength, nand, nor, xor, decoder, neededLine))
{
return true;
}
if (HandleDecoder(lines, listLength, nand, nor, xor, decoder, neededLine))
{
return true;
}
return false;
}
}
}
class Program
{
public static void Main(string[] args)
{
List<BitLine> list = new List<BitLine>();
var bitLineList = new BitLine[200];
for (int i = 0; i < 200; i++) bitLineList[i] = new BitLine();
// set input bit:
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 4; j++)
{
int checker = 1 << j;
bitLineList[j].IsActiveWhenInputIs[i] = ((checker & i) != 0);
}
}
// set zero and one constant bits:
for (int i = 0; i < 16; i++)
{
bitLineList[4].IsActiveWhenInputIs[i] = false;
bitLineList[5].IsActiveWhenInputIs[i] = true;
}
list.AddRange(bitLineList);
var neededBitLine = new BitLine();
for (int i = 0; i < 16; i++)
{
neededBitLine.IsActiveWhenInputIs[i] = (i%7==0); // be true for any number that is devideble by 7 (0,7,14)
}
var solver = new Solver();
Console.WriteLine(solver.Solve(list, 6, true, true, true, true, neededBitLine));
Console.ReadKey();
}
}
}
หวังว่าคราวนี้มันจะเป็นคำอธิบายที่ถูกต้อง: P