23多米诺骨牌(2)

来源:互联网 发布:centos7 yum安装lnmp 编辑:程序博客网 时间:2024/06/04 19:30

智力游戏



多米诺骨牌问题都可以大致分成2大步

第一步,让每一行每一列的和符合要求

第二步,仅仅通过调整行和列的顺序,使得对角线也符合要求

第一步是肯定可以实现的,但是实现了第一步之后,能否继续实现第二步就不一定了。


第一步,要使每行每列以及两对角线的和均为13

注意到,28块每块的2个数之和分别为012233444555,666677788899,10,10,11,12

其中任意18块的和最小为76

现在要找出18块,和为78,因为和76隔的不多,所以肯定有一些规律可循。

最后的结果是:01223344455666必选,剩余的4块只有4种情况,分别为6777,5688,5679,5778

18个数字分成6组(对应着6列),每组的和都是13,可以手算出来所有的情况:


012233444556666777有3种分组方法 
067 166 247 256 337 445
067 166 247 247 355 346
067 157 247 256 346 346


012233444555666688有1种分组方法
058 148 256 256 346 346

012233444555666679有5种分组方法
067 139 256 256 346 445
049 157 256 256 346 346
049 166 256 256 337 445
067 166 229 346 355 445
049 166 247 256 346 355


012233444555666778有7种分组方法
058 157 247 256 346 346
067 157 256 238 346 445
067 148 256 256 337 445
058 166 247 256 337 445
067 148 247 256 346 355
067 166 238 247 355 445
058 166 247 247 346 355


然后将18个数字分成3组(对应着3大行),上面显示的每3个连续的数都分别出现在不同的组中,每组的和都是26

这个自己试试就能解决,也可以编程求出所有的解,毕竟不一定所有的情况都能顺利完成第二步。

分组代码:

#include<iostream>using namespace std;int change(int n)//将3位数abc换成cab{int c = n % 10;int ab = n / 10;return ab + c * 100;}int main(){int num[6], nu[6];//nu的作用是把abc换成acbint number[6][6];//number的一行就是abc,cab,bca,acb,bac,cba//如果abc3个数字有重复的,只要让nu为0,那么后面3个就都是0,这么做是为了避免输出重复
//而且还可以减少一些重复计算
int sum36 = 0;//sum36是输入的18个数码的和,也就是36个点数之和
for(int i = 0; i < 6; i++)
{cin >> num[i];sum36 += num[i] / 100 + (num[i] / 10) % 10 + num[i] % 10;int c = num[i] % 10;int ab = num[i] / 10;nu[i] = ab * 10 - ab % 10 * 9 + c * 10;if (nu[i] == num[i] || nu[i] == change(num[i]) || nu[i] == change(change(num[i])))nu[i] = 0;//判断abc3个字母有没有重复的
number[i][0] = num[i];number[i][3] = nu[i];
for (int j = 0; j < 5; j++)if (j != 2)
number[i][j + 1] = change(number[i][j]);
}

sum36 /= 3;
int n1, n2, n3, n4, n5, n6;int sum;
for (int j1 = 0; j1 < 6; j1++)if (number[1][j1])
for (int j2 = 0; j2 < 6; j2++)if (number[2][j2])
for (int j3 = 0; j3 < 6; j3++)if (number[3][j3])
for (int j4 = 0; j4 < 6; j4++)if (number[4][j4])
for (int j5 = 0; j5 < 6; j5++)if (number[5][j5])
for (int j6 = 0; j6 < 6; j6++)if (number[0][j6]){n1 = number[1][j1];n2 = number[2][j2];n3 = number[3][j3];n4 = number[4][j4];n5 = number[5][j5];n6 = number[0][j6];sum = n1 + n2 + n3 + n4 + n5 + n6;if (sum != sum36 * 111)continue;if ((n1 % 10 + n2 % 10 + n3 % 10 + n4 % 10 + n5 % 10 + n6 % 10) != sum36)continue;printf("%03d,%03d,%03d,%03d,%03d,%03d\n", n1, n2, n3, n4, n5, n6);}cout << "end§";system("pause>nul");return 0;}

输入:067 166 247 256 337 445

输出:

166,247,625,733,445,670
166,247,526,733,544,670
166,247,526,733,454,760
166,724,562,373,454,607

......

661,742,625,337,445,076
661,742,625,337,454,067
661,742,526,337,544,076
end§

这样,任选一行就可以完成差不多第一步了。

比如,我就选第一行:166,247,625,733,445,670


最后一小步是把某些块上下倒置,使得每一行的和都为13



第二步,仅仅通过调整行和列的顺序,使得对角线的和也为13

这个手动实现比较麻烦,但是编程却比较容易,无法就是枚举各种顺序

把上图中的36个数字硬编码到数组num中,运行即可得到答案

代码:

#include<iostream>using namespace std;int num[6][6]={0,2,4,1,3,3,1,0,2,6,1,3,6,0,1,0,2,4,0,4,1,3,2,3,5,5,0,1,2,0,1,2,5,2,3,0};////////////////////////需要硬编码进来void change_column(int j1, int j2)//把这2列的数据交换{for (int i = 0; i < 6; i++){int temp = num[i][j1];num[i][j1] = num[i][j2];num[i][j2] = temp;}}void change_row(int i1, int i2)//把这2行的数据交换//这个函数除了在choose中调用外,只能被调用成change_row(0,1)、change_row(2,3)、change_row(4,5)三种//而且由于对称性,change_row(2,3)是不需要调用的{for (int j = 0; j < 6; j++){int temp = num[i1][j];num[i1][j] = num[i2][j];num[i2][j] = temp;}}void choose(int i)//这个函数只能被调用成choose(0)、choose(2)、choose(4)三种情况{change_row(i, 2);change_row(i + 1, 3);}bool ok(int sum)//检查2条对角线的和是否和1列的和相同{int t = 0;for (int i = 0; i < 6; i++)t += num[i][i];if (t != sum)return false;t = 0;for (int i = 0; i < 6; i++)t += num[i][5 - i];if (t != sum)return false;return true;}int out(){for (int i = 0; i < 6; i++){for (int j = 0; j < 6; j++)cout << num[i][j] << "  ";cout << endl;}system("pause>nul");return 0;}int main(){int sum = 0;for (int i = 0; i < 6; i++)sum += num[i][0];for (int i = 0; i < 6; i++){change_column(0, i);for (int i = 1; i < 6; i++){change_column(1, i);for (int i = 2; i < 6; i++){change_column(2, i);for (int i = 3; i < 6; i++)
{change_column(3, i);for (int i = 4; i < 6; i++){change_column(4, i);for (int i = 5; i < 6; i++){change_column(5, i);for (int i = 0; i < 6; i += 2){choose(i);if (ok(sum))return out();change_row(4, 5);if (ok(sum))return out();change_row(0, 1);if (ok(sum))return out();}}}}
}
}
}}
输出:

6  2  1  0  4  0
0  2  1  3  3  4
5  2  0  1  0  5
1  3  5  2  0  2
0  3  4  1  3  2
1  1  2  6  3  0


这样便过关了。

1 0
原创粉丝点击