У меня есть мнимое оборудование. Он имеет ровно 2 адреса памяти и 2 регистра. Он имеет только две инструкции - вычесть адрес памяти из регистра и переместить значение регистра в память. Ему необходимо выполнить операцию перемещения значения с одного адреса памяти на другой. Каждое из четырех значений в памяти и регистрах имеет неизвестные значения. Все это выглядит следующим образом:Как рассчитать оптимальное решение?
Хранение:
Memory #1 (m1) -> a
Memory #2 (m2) -> b
Register #1 (r1) -> c
Register #2 (r2) -> d
Инструкции:
mov m r //Copies value at r into m
sub r m //Subtracts the value in m from r
Возможные комбинации:
mov m1 r1
mov m1 r2
mov m2 r1
mov m2 r2
sub r1 m1
sub r1 m2
sub r2 m1
sub r2 m2
Цель:
Set the value in m2 to equal a (which is the value initially stored in m1).
Возможное решение (Спойлер оповещения!):
//Comments show respective value for m1, m2, r1, r2
//a b c d
mov m2 r1 //a c c d
sub r1 m2 //a c 0 d
mov m2 r1 //a 0 0 d
sub r1 m1 //a 0 -a d
mov m1 r1 //-a 0 -a d
sub r1 m1 //-a 0 0 d
sub r1 m1 //-a 0 a d
mov m2 r1 //-a a a d
Это решение принял 8 ходов. Я пытался найти лучшее решение, написав программу для перебора всех решений (до 10 ходов). Я написал его на Java. Это то, что я придумал:
import java.util.ArrayList;
import java.util.Random;
public class AssemblyChallenge {
//This is the main logic.
public static void main(String[] args) {
Memory memory1 = new Memory();
Memory memory2 = new Memory();
while (memory1.value == memory2.value) {
memory2 = new Memory();
}
Register register1 = new Register();
Register register2 = new Register();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 8; k++) {
for (int l = 0; l < 8; l++) {
for (int m = 0; m < 8; m++) {
for (int n = 0; n < 8; n++) {
for (int o = 0; o < 8; o++) {
for (int p = 0; p < 8; p++) {
for (int q = 0; q < 8; q++) {
for (int r = 0; r < 8; r++) {
ArrayList<Integer> instructions = new ArrayList<>();
instructions.add(i);
instructions.add(j);
instructions.add(k);
instructions.add(l);
instructions.add(m);
instructions.add(n);
instructions.add(o);
instructions.add(p);
instructions.add(q);
instructions.add(r);
runInstructions(instructions, memory1, memory2, register1, register2);
}
}
}
}
}
}
}
}
}
}
}
//This runs an set of instruction sets
public static void runInstructions(ArrayList<Integer> instructions, Memory memory1, Memory memory2, Register register1, Register register2) {
int memoryValue1 = memory1.value;
for (int instruction : instructions) {
switch (instruction) {
case 0:
moveRegisterIntoMemory(memory1, register1);
break;
case 1:
moveRegisterIntoMemory(memory1, register2);
break;
case 2:
moveRegisterIntoMemory(memory2, register1);
break;
case 3:
moveRegisterIntoMemory(memory2, register2);
break;
case 4:
subtractMemoryFromRegister(register1, memory1);
break;
case 5:
subtractMemoryFromRegister(register1, memory2);
break;
case 6:
subtractMemoryFromRegister(register2, memory1);
break;
case 7:
subtractMemoryFromRegister(register2, memory2);
break;
}
if (memoryValue1 == memory2.value) {
// System.out.println(instructions + " succeeded in 10 moves or less!");
}
System.out.println(instructions.size());
}
}
//This takes the value in the register and copies it into the value at the memory
public static void moveRegisterIntoMemory(Memory memory, Register register) {
memory.value = register.value;
}
//This takes the value in the memory and subtracts it from the value in the register
public static void subtractMemoryFromRegister(Register register, Memory memory) {
register.value -= memory.value;
}
//This is the Memory class which stores a random value
static class Memory {
public int value;
public Memory() {
Random random = new Random();
value = random.nextInt(20000) - 10000;
}
}
//This is the Register class which stores a random value
static class Register {
public int value;
public Register() {
Random random = new Random();
value = random.nextInt(20000) - 10000;
}
}
}
Эта проблема в том, что он работает слишком медленно, и это не кажется, что он будет рассчитывать 1073741824 возможностей в реалистичное время. Как я могу исправить свою программу, чтобы найти оптимальное решение этой проблемы? Есть ли у вас подход с грубой силой?
Зачем вам это нужно? –
@ KristofferE Для удовольствия. Учить. – Evorlor
Один из способов оптимизировать этот код, по крайней мере, немного, не сохраняйте все наборы заданий. Вместо того, чтобы генерировать набор инструкций, а затем добавлять их в arraylist, немедленно оцените его, распечатайте решение и перейдите к следующей комбинации. Таким образом, вы, по крайней мере, не будете есть всю память - если моя математика правильная, все инструкции наборы берут не менее 40 ГБ в необработанных данных. (1073741824 комбинаций * 10 номеров * 4 байта на int). – CptBartender