找回密码
 欢迎注册
楼主: gxqcn

[分享] 取牙签智力游戏

[复制链接]
发表于 2014-1-21 11:20:53 | 显示全部楼层
8#的问题,如何编个程序来计算一下在四堆的情况下,应该留给对手什么样的局面?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 13:48:19 | 显示全部楼层
hujunhua 发表于 2014-1-21 11:20
8#的问题,如何编个程序来计算一下在四堆的情况下,应该留给对手什么样的局面?


用c++粗略地写了一个复杂度为`O(N^6)`的程序(`N`为预编译可调整参数)。

功能是每次输入四个数`x,y,z,w \leq N`,输出`(x,y,z,w)`对应的状态先手胜或负。

另外,我还发现了一些有趣的东西,就先不说出来了。用来验证这些有趣的东西的代码并没有删去。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <memory.h>

  4. #define N 30

  5. using namespace std;

  6. bool f[N + 1][N + 1][N + 1][N + 1];

  7. bool check(int x, int y, int z, int w)
  8. {
  9.     int a[4], b[40], t, q;
  10.     a[0] = x; a[1] = y; a[2] = z; a[3] = w;
  11.     memset(b, 0, sizeof(b));
  12.     for (int i = 0; i < 4; i++)
  13.     {
  14.         t = 1; q = 0;
  15.         while (a[i])
  16.         {
  17.             if (a[i] & t)
  18.             {
  19.                 b[q]++;
  20.                 a[i] -= t;
  21.             }
  22.             t *= 2;
  23.             q++;
  24.         }
  25.     }
  26.     for (int i = 0; i < 40; i++) if (b[i] % 3 != 0) return 0;
  27.     return 1;
  28. }

  29. int main()
  30. {
  31.     bool flag;
  32.     for (int a = 0; a <= N; a++)
  33.         for (int b = 0; b <= N; b++)
  34.             for (int c = 0; c <= N; c++)
  35.                 for (int d = 0; d <= N; d++)
  36.                 {
  37.                     flag = 0;
  38.                     for (int i = 0; i < a; i++) if (!f[i][b][c][d]) flag = 1;
  39.                     for (int i = 0; i < b; i++) if (!f[a][i][c][d]) flag = 1;
  40.                     for (int i = 0; i < c; i++) if (!f[a][b][i][d]) flag = 1;
  41.                     for (int i = 0; i < d; i++) if (!f[a][b][c][i]) flag = 1;
  42.                     for (int i = 0; i < a; i++)
  43.                         for (int j = 0; j < b; j++) if (!f[i][j][c][d]) flag = 1;
  44.                     for (int i = 0; i < a; i++)
  45.                         for (int j = 0; j < c; j++) if (!f[i][b][j][d]) flag = 1;
  46.                     for (int i = 0; i < a; i++)
  47.                         for (int j = 0; j < d; j++) if (!f[i][b][c][j]) flag = 1;
  48.                     for (int i = 0; i < b; i++)
  49.                         for (int j = 0; j < c; j++) if (!f[a][i][j][d]) flag = 1;
  50.                     for (int i = 0; i < b; i++)
  51.                         for (int j = 0; j < d; j++) if (!f[a][i][c][j]) flag = 1;
  52.                     for (int i = 0; i < c; i++)
  53.                         for (int j = 0; j < d; j++) if (!f[a][b][i][j]) flag = 1;
  54.                     f[a][b][c][d] = flag;
  55.                 }
  56.    
  57.     /*
  58.     for (int a = 0; a <= N; a++)
  59.         for (int b = 0; b <= N; b++)
  60.             for (int c = 0; c <= N; c++)
  61.                 for (int d = 0; d <= N; d++)
  62.                     if (f[a][b][c][d] ^ !check(a, b, c, d)) cout << "ERROR " << a << " " << b << " " << c << " " << d << endl;
  63.     */
  64.    
  65.     cout << "Preprocessing completed.\n";
  66.    
  67.     while (1)
  68.     {
  69.         int x, y, z, w;
  70.         cin >> x >> y >> z >> w;
  71.         if (f[x][y][z][w]) cout << "WIN\n"; else cout << "LOSE\n";
  72.     }
  73. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 17:54:09 | 显示全部楼层
不要这种检验程序,要的是生成程序,比如限制每堆数量小于100. 我手工计算,应该留给对手的局面是:
{1,2,3,4}, {1,5,6,7}, {1,8,9,10}, {1,11,12,13}, ..., {1,3a-1,3a,3a+1}, ..., {1,95,96,97}, {1,98,99,100};
{2,5,8,9}, {2,6,10,11), {2,7,12,13}, {2,14,17,18}, {2,15,19,20}, {2,16,21,22}, ..., {2,5+9a+b,8+9a+b,9+9a+b}(b=0,1,2), ..., {2,95,98,99};
{3,5,10,11}, {3,6,8,10},{3,7,14,15}, {3,9,12,16}, {3,13,17,20}, {3,18,21,23}, {3,19,22,24},.....

应该可以编一种递归程序。

点评

这个检验程序稍稍修改一下就是生成程序啦…… : )  发表于 2014-1-21 18:34
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 18:47:18 | 显示全部楼层
hujunhua 发表于 2014-1-21 17:54
不要这种检验程序,要的是生成程序,比如限制每堆数量小于100. 我手工计算,应该留给对手的局面是:
{1,2, ...


我修改了一下,另外还上传了一个编译后的可执行文件,希望能满足你的要求。(需要`N \leq 50`)

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <conio.h>

  4. #define NN 50

  5. using namespace std;

  6. bool f[NN + 1][NN + 1][NN + 1][NN + 1];

  7. int main()
  8. {
  9.     int N;
  10.     bool flag;
  11.     cout << "Input N (not greater than " << NN << ") = ";
  12.     cin >> N;
  13.     for (int a = 0; a <= N; a++)
  14.         for (int b = 0; b <= N; b++)
  15.             for (int c = 0; c <= N; c++)
  16.                 for (int d = 0; d <= N; d++)
  17.                 {
  18.                     flag = 0;
  19.                     for (int i = 0; i < a; i++) if (!f[i][b][c][d]) flag = 1;
  20.                     for (int i = 0; i < b; i++) if (!f[a][i][c][d]) flag = 1;
  21.                     for (int i = 0; i < c; i++) if (!f[a][b][i][d]) flag = 1;
  22.                     for (int i = 0; i < d; i++) if (!f[a][b][c][i]) flag = 1;
  23.                     for (int i = 0; i < a; i++)
  24.                         for (int j = 0; j < b; j++) if (!f[i][j][c][d]) flag = 1;
  25.                     for (int i = 0; i < a; i++)
  26.                         for (int j = 0; j < c; j++) if (!f[i][b][j][d]) flag = 1;
  27.                     for (int i = 0; i < a; i++)
  28.                         for (int j = 0; j < d; j++) if (!f[i][b][c][j]) flag = 1;
  29.                     for (int i = 0; i < b; i++)
  30.                         for (int j = 0; j < c; j++) if (!f[a][i][j][d]) flag = 1;
  31.                     for (int i = 0; i < b; i++)
  32.                         for (int j = 0; j < d; j++) if (!f[a][i][c][j]) flag = 1;
  33.                     for (int i = 0; i < c; i++)
  34.                         for (int j = 0; j < d; j++) if (!f[a][b][i][j]) flag = 1;
  35.                     f[a][b][c][d] = flag;
  36.                 }
  37.     cout << "Preprocessing completed. I'll output the result to "result.txt".\n";
  38.     FILE *fout;
  39.     fout = fopen("result.txt", "w");
  40.     fprintf(fout, "The LOSE states are:\n");
  41.     for (int a = 0; a <= N; a++)
  42.         for (int b = a; b <= N; b++)
  43.             for (int c = b; c <= N; c++)
  44.                 for (int d = c; d <= N; d++)
  45.                     if (!f[a][b][c][d])
  46.                         fprintf(fout, "(%d,%d,%d,%d)\n", a, b, c, d);
  47.     fclose(fout);
  48.     cout << "Completed. Press anykey to continue...\n";
  49.     getch();
  50. }
复制代码

prog.rar

116.21 KB, 下载次数: 5, 下载积分: 金币 -1 枚, 经验 1 点, 下载 1 次

售价: 1 枚金币  [记录]  [购买]

评分

参与人数 1威望 +4 金币 +8 贡献 +6 经验 +6 鲜花 +12 收起 理由
hujunhua + 4 + 8 + 6 + 6 + 12 开端之功

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 18:56:07 | 显示全部楼层
hujunhua 发表于 2014-1-21 17:54
不要这种检验程序,要的是生成程序,比如限制每堆数量小于100. 我手工计算,应该留给对手的局面是:
{1,2, ...

对你的{1,2,3,4}略有疑问,因为它不出现在我的程序打印出来的结果中。我们来试试,我先。如果你感兴趣的话可以直接点评在这个贴子上。
{1,2,3,4}->{1,2,3,3}

点评

{1,2,3,4}果然错了,那么后面的都得错。我按4个数中不应有两数相等者首先得到1234,应该是不能有较小的相等者。  发表于 2014-1-22 00:44
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 21:16:41 | 显示全部楼层
  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4. #define NN 99
  5. int dmap[NN+1][NN+1];
  6. #define CREATE_DATA(a,b) ((a)*(NN+1)+(b))
  7. void init_dmap()
  8. {
  9.     int i;
  10.     for(i=1;i<=NN;i++){
  11.        dmap[0][i]=CREATE_DATA(i,i);
  12.        dmap[i][i]=CREATE_DATA(0,i);
  13.     }
  14. }

  15. int get_eq_cd(int a, int b, int& c, int& d)
  16. {
  17.     int r=dmap[a][b];
  18.     if(r==0)return 0;
  19.     c=r/(NN+1);
  20.     d=r%(NN+1);
  21.     return 1;
  22. }

  23. void add_eq_data(int a, int b, int c, int d)
  24. {
  25.     if(b>NN)return;
  26.     dmap[a][b]=CREATE_DATA(c,d);
  27.     if(c>NN)return;
  28.     dmap[a][c]=CREATE_DATA(b,d);
  29.     dmap[b][c]=CREATE_DATA(a,d);
  30.     if(c>NN)return;
  31.     dmap[a][d]=CREATE_DATA(b,d);
  32.     dmap[b][d]=CREATE_DATA(a,c);
  33.     dmap[c][d]=CREATE_DATA(a,b);
  34.     printf("%d,%d,%d,%d\n",a,b,c,d);
  35. }



  36. int main()
  37. {
  38.     init_dmap();
  39.     for (int a = 1; a <= NN; a++)
  40.         for (int b = a; b <= NN; b++){
  41.             int c,d;
  42.             if(dmap[a][b]!=0)continue;
  43.             for (c = b; c <= NN; c++){
  44.                 for (d = c; d <= NN; d++)
  45.                 {
  46.                     int x,y;bool found=false;
  47.                     if(get_eq_cd(a,c,x,y)&&x<=b&&y<=d)found=true;
  48.                     if(!found&&get_eq_cd(a,d,x,y)&&x<=b&&y<=c)found=true;
  49.                     if(!found&&get_eq_cd(b,c,x,y)&&x<=a&&y<=d)found=true;
  50.                     if(!found&&get_eq_cd(b,d,x,y)&&x<=a&&y<=c)found=true;
  51.                     if(!found&&get_eq_cd(c,d,x,y)&&x<=a&&y<=b)found=true;
  52.                     if(!found){
  53.                        add_eq_data(a,b,c,d);
  54.                        break;
  55.                     }
  56.                 }
  57.                 if(d<=NN)break;
  58.             }
  59.            
  60.         }
  61.        return 0;  
  62. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-21 21:40:03 来自手机 | 显示全部楼层
想错了,我这方法好想不行。我程序中映射要改多值才行

点评

期待mathe的高效算法,楼上O(N^6), 貌似有降次空间哪  发表于 2014-1-22 01:49
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-22 00:47:08 | 显示全部楼层
取N<=30, 上面的程序输出结果为:
(1,2,3,3)
(1,4,5,5)
(1,6,7,7)
(1,8,9,9)
(1,10,11,11)
(1,12,13,13)
(1,14,15,15)
(1,16,17,17)
(1,18,19,19)
(1,20,21,21)
(1,22,23,23)
(1,24,25,25)
(1,26,27,27)
(1,28,29,29)
(2,4,6,6)
(2,5,7,7)
(2,8,10,10)
(2,9,11,11)
(2,12,14,14)
(2,13,15,15)
(2,16,18,18)
(2,17,19,19)
(2,20,22,22)
(2,21,23,23)
(2,24,26,26)
(2,25,27,27)
(2,28,30,30)
(3,4,7,7)
(3,5,6,7)
(3,8,11,11)
(3,9,10,11)
(3,12,15,15)
(3,13,14,15)
(3,16,19,19)
(3,17,18,19)
(3,20,23,23)
(3,21,22,23)
(3,24,27,27)
(3,25,26,27)
(4,8,12,12)
(4,9,13,13)
(4,10,14,14)
(4,11,15,15)
(4,16,20,20)
(4,17,21,21)
(4,18,22,22)
(4,19,23,23)
(4,24,28,28)
(4,25,29,29)
(4,26,30,30)
(5,8,13,13)
(5,9,12,13)
(5,10,15,15)
(5,11,14,15)
(5,16,21,21)
(5,17,20,21)
(5,18,23,23)
(5,19,22,23)
(5,24,29,29)
(5,25,28,29)
(6,8,14,14)
(6,9,15,15)
(6,10,12,14)
(6,11,13,15)
(6,16,22,22)
(6,17,23,23)
(6,18,20,22)
(6,19,21,23)
(6,24,30,30)
(6,26,28,30)
(7,8,15,15)
(7,9,14,15)
(7,10,13,15)
(7,11,12,15)
(7,11,13,14)
(7,16,23,23)
(7,17,22,23)
(7,18,21,23)
(7,19,20,23)
(7,19,21,22)
(7,27,29,30)
(8,16,24,24)
(8,17,25,25)
(8,18,26,26)
(8,19,27,27)
(8,20,28,28)
(8,21,29,29)
(8,22,30,30)
(9,16,25,25)
(9,17,24,25)
(9,18,27,27)
(9,19,26,27)
(9,20,29,29)
(9,21,28,29)
(10,16,26,26)
(10,17,27,27)
(10,18,24,26)
(10,19,25,27)
(10,20,30,30)
(10,22,28,30)
(11,16,27,27)
(11,17,26,27)
(11,18,25,27)
(11,19,24,27)
(11,19,25,26)
(11,23,29,30)
(12,16,28,28)
(12,17,29,29)
(12,18,30,30)
(12,20,24,28)
(12,21,25,29)
(12,22,26,30)
(13,16,29,29)
(13,17,28,29)
(13,20,25,29)
(13,21,24,29)
(13,21,25,28)
(13,23,27,30)
(14,16,30,30)
(14,18,28,30)
(14,20,26,30)
(14,22,24,30)
(14,22,26,28)
(14,23,27,29)
(15,19,29,30)
(15,21,27,30)
(15,22,27,29)
(15,23,25,30)
(15,23,26,29)
(15,23,27,28)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-22 01:24:43 | 显示全部楼层
{1,2a,2a+1,2a+1}
{2,4a+b,4a+b+2,4a+b+2} (b=0,1)
{3,4a,4a+3,4a+3},{3,4a+1,4a+2,4a+3}
{4,8a+b,8a+b+4,8a+b+4}(b=0,1,2,3)
{5,8a+b,8a+b+5,8a+b+5},{5,8a+b+1,8a+b+4,8a+b+5}(b=0,2)
{6,8a+b,8a+b+6,8a+b+6},{6,8a+b+2,8a+b+4,8a+b+6}(b=0,1)

当最小数为\( 2^n \)时,猜想为:\( 2^n*\{1,2,3,3\}+\left( 2^{n+1}k+a \right)*\{0,1,1,1\},\left( k\geq0,a=0,1,2,\cdots,2^n-1 \right) \)
看到周期仍然与\( 2^n \)有关,还是化成二进数么?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2014-1-24 16:42:57 | 显示全部楼层
的确结果同二进制相关,不同的二进制位可以分开处理,结果非常简单。hujunhua出的这个题目很棒呀。而且每次允许取三堆或四堆等结论类似。

点评

有链接吗?我google查不到呀  发表于 2014-1-24 20:11
我查了一下,这被称为k-nim问题,但是在wikipedia上似乎没有相关叙述。  发表于 2014-1-24 19:36
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-5 01:03 , Processed in 0.046814 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表