C程序重新排列跳棋
C program rearrange checkers
我想看看我是否可以将这个名为移动西洋跳棋的数学难题编写成 C 程序。假设我们有 4 个空位和 6 个黑白交替的棋子
比如这个 0,0,0,0,b,w,b,w,b,w
现在您只能成对移动跳棋。一次 2 个,将它们滑到空位,您不能打乱它们的顺序。这本书展示了这通过 3 个步骤完成,如下所示。
0,0,0,0,b,w,b,w,b,w 开始
0,0,w,b,b,0,0,w,b,w 第一关
0,0,w,b,b,b,w,w,0,0 秒通过
w,w,w,b,b,b,0,0,0,0 第三遍
我研究过合并排序和冒泡排序等算法。但它们似乎对我来说不是什么有用的代码来解决这个问题。
我考虑过将其放入数组中。 运行 来自 4-9 的 for 循环,因为它们不为空。比较左右,然后有逻辑移动它。但是我对如何在 C 代码中实现这一点感到困惑。 for 循环和比较不是问题。这是移动它们的逻辑,直到我一开始就得到三个白色的棋子。
下面是我的代码。 while 循环不再输出任何内容
#include<stdio.h>
int main ()
{
char checkers[10] = {0,0,0,0,'b','w','b','w','b','w'};
int a,temp1,temp2,cntr;
cntr = 1;
int i;
//check each value right and left adjacent
printf("%d a position",a);
while(!(checkers[0] == 'w') && !(checkers[1] == 'w') && !(checkers[2] == 'w'))
{
for(a=4;a>9;a++){
// if 3 white in a row followed by 3 black in a row done and exit
printf("%d a position\n",a);
if(checkers[0] == 'w' && checkers[1] == 'w' && checkers[2] == 'w' && checkers[3] == 'b' && checkers[4] == 'b' && checkers[5] == 'b')
{
printf("workd");
for(i=0;i<(sizeof(checkers)/sizeof (checkers[0]));i++)
{
printf("Checkers have finished being moved result is:%c",checkers[i]);
break;
}
}
//once w and b found move it to empty space 2 and 3
if(checkers[a-1] == 'b' && checkers[a+1] == 'b')
{
//check if 2-3 position is empty
if(checkers[1] == 0 && checkers[2] == 0)
{
temp1 = checkers[a];
temp2 = checkers[a+1];
checkers[cntr] = temp1;
checkers[cntr+1] = temp2;
break;
}
}
// looking for b followed by w, checking if 6 and 7th spot is empty
// then moving it into that spot
if(checkers[a-1] == 'w' && checkers[a+1] == 'w' && checkers[2] == 'b' && checkers[5] && checkers[6] == 0)
{
temp1 = checkers[a];
temp2 = checkers[a+1];
checkers[5] = temp1;
checkers[6] = temp2;
// move 2 and 3 down one
temp1 = checkers[1];
temp2 = checkers[2];
checkers[2+1] = temp1;
checkers[1+1] = temp2;
// finally move two whites to the front
temp1 = checkers[8];
temp2 = checkers[9];
checkers[0] = temp1;
checkers[1] = temp2;
break;
}
}
}
}
/*
just shows what swapping looks like
{0,0,0,0,b,w,b,w,b,w};
{0,w,b,0,b,0,0,w,b,w};
{0,w,b,0,b,b,w,w,0,0};
{0,0,w,b,b,b,w,w,0,0};
*/
我正在做很多移动,它最终应该会被正确放置。我难过的是,可能有一些数学方法和算法来解决这类问题。所以想知道它如何在代码中工作。我的代码是根据我已经弄清楚的内容来安排它,以使其匹配。如果开始时空白空间的数量发生变化或添加了更多片段怎么办?我研究了堆排列排序和冒泡排序,但它在示例中一次显示一项被移动。
有一个意见是对的,没有通用的排序算法,稍后你会看到问题是缺少严格的顺序。
因此,让我们尝试从头开始设计一个。这个答案并不完整,只是关于如何解决此类问题的想法。
由于您的代码片段是已知方法的实现,因此不会有太大帮助。
那么让我们开始吧:
您的第一种方法不应该在意运行时的复杂性,而是获取正确的对象。我们试图概括。
已经评论说双元素交换是关键。
所以有 9(n) 个元素使它成为 n-1 对。这些是您拥有的字母表的有序对。
这些是00 0w 0b w0 ww wb b0 bw bb
,
给他们起个新名字可能会有帮助,比如
A B C D E F G H I
数学上它们与第二个版本的一些限制相同:
A 只能跟随 B 和 C 等等。
你可以只写两个方法来翻译它们。所有交换和检查操作都将在此版本上完成。
这里是缺少订单的问题 obviuos:就像没有答案是 greater/smaller 例如D 和 G 对于排序算法的问题没有任何价值。也许以后会有。
交换:一个必须是 A=00
,另一个必须与那个相距超过 1 个索引。这使得识别互换指数的一侧变得容易(冷是最多 2 个元素)(或在均衡分配层(n/3))
交换后,邻居元素改变了它们的值!
我们想去的地方:我们需要某处序列 www
意味着一个必须是 E 和一个额外的 w,所以我们需要寻找 BE, ED, EF, HE
,广义 BE..E, E..ED, E..EF, HE..E
核心算法:一步一个脚印,有点递归的意思。从中我们可以检查机会树*。当没有 A
了(没有地方可以交换)时,我们处于死胡同,所以我们停止递归或者我们找到了解决方案 www
如果我们只寻找一个解决方案,否则附加路径那棵树到解决方案列表,直到你有足够的。
因此,遍历所有 A
s,然后遍历距它一个索引的其余索引。
每个迭代将具有 A (a) 的参数交换索引、另一个交换索引 (i) 和您的数组 T
通常您现在会在递归树中寻找模式和机会:
第一:交换永远不会破坏 A,所以总是有机会继续,但是:新的交换对不能是旧的(它会回到树中)。遍历不会结束(因为总是有一个 A),所以没有直接的递归调用或至少递归深度的中断条件。可以通过必须检查的树创建一个任务列表,每个元素包含 (a,i,T)
或序列 [(a0,i0),...,(an,in)]
并且您的递归调用将替换为将此元素添加到列表中。
其次:不断变化的邻居中的模式:如果一个人想创建 E
s 有通往它们的方法(只需检查哪些方法结合到 ww
)这些是交换的主要候选者,它们越近,它们就越应该被优先考虑。由于这些方式是有限的,所以它们偶尔会重复一次。使用该模式,交换选项会大大减少。这些模式也可以被你的新字母表的序列所取代。因此,您会寻找三元组,例如 'BAH' 和 'CDC',它们在交换内部字母时会变成新的三元组。这可以制表,然后可以对 table 进行评级、排序,并且在检查时需要应用此顺序。
既然您直接询问了关于如何处理此类问题的数学或算法方法,那么这应该是一种看待事物的方法。一般来说:花时间给你的结构命名。或者说到编程,我想应该是 Stroustrup 曾经说过的话:如果你能想到,就把它做成 class!
*致所有喜欢评论的人:bruteforce...指数复杂度yadda yadda,我完全知道,这是设计步骤!
我想看看我是否可以将这个名为移动西洋跳棋的数学难题编写成 C 程序。假设我们有 4 个空位和 6 个黑白交替的棋子 比如这个 0,0,0,0,b,w,b,w,b,w
现在您只能成对移动跳棋。一次 2 个,将它们滑到空位,您不能打乱它们的顺序。这本书展示了这通过 3 个步骤完成,如下所示。
0,0,0,0,b,w,b,w,b,w 开始
0,0,w,b,b,0,0,w,b,w 第一关
0,0,w,b,b,b,w,w,0,0 秒通过
w,w,w,b,b,b,0,0,0,0 第三遍
我研究过合并排序和冒泡排序等算法。但它们似乎对我来说不是什么有用的代码来解决这个问题。
我考虑过将其放入数组中。 运行 来自 4-9 的 for 循环,因为它们不为空。比较左右,然后有逻辑移动它。但是我对如何在 C 代码中实现这一点感到困惑。 for 循环和比较不是问题。这是移动它们的逻辑,直到我一开始就得到三个白色的棋子。
下面是我的代码。 while 循环不再输出任何内容
#include<stdio.h>
int main ()
{
char checkers[10] = {0,0,0,0,'b','w','b','w','b','w'};
int a,temp1,temp2,cntr;
cntr = 1;
int i;
//check each value right and left adjacent
printf("%d a position",a);
while(!(checkers[0] == 'w') && !(checkers[1] == 'w') && !(checkers[2] == 'w'))
{
for(a=4;a>9;a++){
// if 3 white in a row followed by 3 black in a row done and exit
printf("%d a position\n",a);
if(checkers[0] == 'w' && checkers[1] == 'w' && checkers[2] == 'w' && checkers[3] == 'b' && checkers[4] == 'b' && checkers[5] == 'b')
{
printf("workd");
for(i=0;i<(sizeof(checkers)/sizeof (checkers[0]));i++)
{
printf("Checkers have finished being moved result is:%c",checkers[i]);
break;
}
}
//once w and b found move it to empty space 2 and 3
if(checkers[a-1] == 'b' && checkers[a+1] == 'b')
{
//check if 2-3 position is empty
if(checkers[1] == 0 && checkers[2] == 0)
{
temp1 = checkers[a];
temp2 = checkers[a+1];
checkers[cntr] = temp1;
checkers[cntr+1] = temp2;
break;
}
}
// looking for b followed by w, checking if 6 and 7th spot is empty
// then moving it into that spot
if(checkers[a-1] == 'w' && checkers[a+1] == 'w' && checkers[2] == 'b' && checkers[5] && checkers[6] == 0)
{
temp1 = checkers[a];
temp2 = checkers[a+1];
checkers[5] = temp1;
checkers[6] = temp2;
// move 2 and 3 down one
temp1 = checkers[1];
temp2 = checkers[2];
checkers[2+1] = temp1;
checkers[1+1] = temp2;
// finally move two whites to the front
temp1 = checkers[8];
temp2 = checkers[9];
checkers[0] = temp1;
checkers[1] = temp2;
break;
}
}
}
}
/*
just shows what swapping looks like
{0,0,0,0,b,w,b,w,b,w};
{0,w,b,0,b,0,0,w,b,w};
{0,w,b,0,b,b,w,w,0,0};
{0,0,w,b,b,b,w,w,0,0};
*/
我正在做很多移动,它最终应该会被正确放置。我难过的是,可能有一些数学方法和算法来解决这类问题。所以想知道它如何在代码中工作。我的代码是根据我已经弄清楚的内容来安排它,以使其匹配。如果开始时空白空间的数量发生变化或添加了更多片段怎么办?我研究了堆排列排序和冒泡排序,但它在示例中一次显示一项被移动。
有一个意见是对的,没有通用的排序算法,稍后你会看到问题是缺少严格的顺序。 因此,让我们尝试从头开始设计一个。这个答案并不完整,只是关于如何解决此类问题的想法。
由于您的代码片段是已知方法的实现,因此不会有太大帮助。
那么让我们开始吧:
您的第一种方法不应该在意运行时的复杂性,而是获取正确的对象。我们试图概括。
已经评论说双元素交换是关键。
所以有 9(n) 个元素使它成为 n-1 对。这些是您拥有的字母表的有序对。
这些是00 0w 0b w0 ww wb b0 bw bb
,
给他们起个新名字可能会有帮助,比如
A B C D E F G H I
数学上它们与第二个版本的一些限制相同:
A 只能跟随 B 和 C 等等。
你可以只写两个方法来翻译它们。所有交换和检查操作都将在此版本上完成。
这里是缺少订单的问题 obviuos:就像没有答案是 greater/smaller 例如D 和 G 对于排序算法的问题没有任何价值。也许以后会有。
交换:一个必须是 A=00
,另一个必须与那个相距超过 1 个索引。这使得识别互换指数的一侧变得容易(冷是最多 2 个元素)(或在均衡分配层(n/3))
交换后,邻居元素改变了它们的值!
我们想去的地方:我们需要某处序列 www
意味着一个必须是 E 和一个额外的 w,所以我们需要寻找 BE, ED, EF, HE
,广义 BE..E, E..ED, E..EF, HE..E
核心算法:一步一个脚印,有点递归的意思。从中我们可以检查机会树*。当没有 A
了(没有地方可以交换)时,我们处于死胡同,所以我们停止递归或者我们找到了解决方案 www
如果我们只寻找一个解决方案,否则附加路径那棵树到解决方案列表,直到你有足够的。
因此,遍历所有 A
s,然后遍历距它一个索引的其余索引。
每个迭代将具有 A (a) 的参数交换索引、另一个交换索引 (i) 和您的数组 T
通常您现在会在递归树中寻找模式和机会:
第一:交换永远不会破坏 A,所以总是有机会继续,但是:新的交换对不能是旧的(它会回到树中)。遍历不会结束(因为总是有一个 A),所以没有直接的递归调用或至少递归深度的中断条件。可以通过必须检查的树创建一个任务列表,每个元素包含 (a,i,T)
或序列 [(a0,i0),...,(an,in)]
并且您的递归调用将替换为将此元素添加到列表中。
其次:不断变化的邻居中的模式:如果一个人想创建 E
s 有通往它们的方法(只需检查哪些方法结合到 ww
)这些是交换的主要候选者,它们越近,它们就越应该被优先考虑。由于这些方式是有限的,所以它们偶尔会重复一次。使用该模式,交换选项会大大减少。这些模式也可以被你的新字母表的序列所取代。因此,您会寻找三元组,例如 'BAH' 和 'CDC',它们在交换内部字母时会变成新的三元组。这可以制表,然后可以对 table 进行评级、排序,并且在检查时需要应用此顺序。
既然您直接询问了关于如何处理此类问题的数学或算法方法,那么这应该是一种看待事物的方法。一般来说:花时间给你的结构命名。或者说到编程,我想应该是 Stroustrup 曾经说过的话:如果你能想到,就把它做成 class!
*致所有喜欢评论的人:bruteforce...指数复杂度yadda yadda,我完全知道,这是设计步骤!