我有一些想象中的硬件。它只有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;
}
}
}
这个问题是它运行速度太慢,而且它似乎不会在实际时间内计算1,073,741,824种可能性。如何修复程序以便找到解决此问题的最佳方案?围绕着蛮力的方法吗?
答案 0 :(得分:0)
感谢CptBartender和Harold,我有一个解决方案!它在大约1秒内打印出少于8条指令的所有解决方案。
$('.div').css("width",100-skill) // How to do 100-skill in %?
我只搜索少于8次移动的解决方案,输出为:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class AssemblyChallenge {
//Possible solutions to be confirmed.
private static ArrayList<int[]> solutions = new ArrayList<>();
//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();
int startingMemoryValue1 = memory1.value;
int startingMemoryValue2 = memory2.value;
int startingRegisterValue1 = register1.value;
int startingRegisterValue2 = register2.value;
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++) {
memory1.value = startingMemoryValue1;
memory2.value = startingMemoryValue2;
register1.value = startingRegisterValue1;
register2.value = startingRegisterValue2;
int[] instructions = new int[8];
instructions[0] = i;
instructions[1] = j;
instructions[2] = k;
instructions[3] = l;
instructions[4] = m;
instructions[5] = n;
instructions[6] = o;
instructions[7] = p;
runInstructions(instructions, memory1, memory2, register1, register2);
}
}
}
}
}
}
}
}
confirmSolutions();
}
//This runs an set of instruction sets
public static boolean runInstructions(int[] instructions, Memory memory1, Memory memory2, Register register1, Register register2) {
int memoryValue1 = memory1.value;
int numMoves = 0;
for (int instruction : instructions) {
numMoves++;
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) {
int[] solution = Arrays.copyOfRange(instructions, 0, numMoves);
if (!isSolutionAlreadyFound(solution)) {
solutions.add(solution);
}
return true;
}
}
return false;
}
private static boolean isSolutionAlreadyFound(int[] solution) {
for (int[] foundSolution : solutions) {
if (Arrays.equals(solution, foundSolution)) {
return true;
}
}
return false;
}
private static void confirmSolutions() {
Memory memory1 = new Memory();
Memory memory2 = new Memory();
while (memory1.value == memory2.value) {
memory2 = new Memory();
}
Register register1 = new Register();
Register register2 = new Register();
int startingMemoryValue1 = memory1.value;
int startingMemoryValue2 = memory2.value;
int startingRegisterValue1 = register1.value;
int startingRegisterValue2 = register2.value;
for (int i = 0; i < solutions.size(); i++) {
memory1.value = startingMemoryValue1;
memory2.value = startingMemoryValue2;
register1.value = startingRegisterValue1;
register2.value = startingRegisterValue2;
boolean success = runInstructions(solutions.get(i), memory1, memory2, register1, register2);
if (success && solutions.get(i).length < 8) {
System.out.println(Arrays.toString(solutions.get(i)) + " was successful in " + solutions.get(i).length + " moves!");
}
}
}
//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;
}
}
}
我必须克服的一次打嗝是偶然机会的正确解决方案。我的解决方案只是用不同的数字再次运行检查。当然,这确实有很小的机会产生双重误报。
可能的说明最少为7。
答案 1 :(得分:0)
要将m1移动到m2,仅使用r1的这7个指令序列看起来相当简单:
m1 m2 r1 r2
a b c d
mov r1 m2 c
sub m2 r1 0
sub m1 r1 -a
mov r1 m2 -a
sub m2 r1 0
sub m2 r1 a
mov r1 m2 a
由于没有寄存器来注册指令,因此不包含r2会引起误解,因为它不需要。