点灯游戏是一个十分有趣的智力游戏,他的规则是这样的:
有一行N行N列的灯,开始时全部是灭的, 当你点击其中一盏灯是他的上下左右(若存在的话)状态全部改变,现在要求你在限定的时间内以最少地步数,将全部的灯点亮.
昨天收到了个这封E-mail,回去想了想,今早编了下,出来是基本上出来了,但算法却太过复杂,时间耗费太长,我用的是穷举,大家一起帮忙想想,
我把我的程序附上来:
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#define MAX 10
typedef struct
{
unsigned int st:1;
unsigned int :7; /*构成一个字节*/
}light;
light matrix[MAX][MAX];
int num;
void initial(void);
void tackle(int i);
int main()
{
int test=0,counter=0,i,j;
short *help=NULL;
initial();
puts("Enter a number:");
scanf("%d",&num);
help=(short *)malloc(sizeof(short)*num*num);
for(i=0;i<num*num;i++)
help[i]=0;
while(1)
{
for(i=0;i<num*num;i++)
{
if(!help[i]) /*进行二进制编码 */
{
help[i]=1;
for(j=i-1;j>=0;j--)
help[j]=1-help[j];
break;
}
else test++;
}
if(test==num*num)
break;
else test=0;
for(i=0;i<num*num;i++)
if(help[i]==1)
tackle(i);
if(check())
initial();
else break;
}
for(i=0;i<num*num;i++)
if(help[i]==1)
printf("STEP%02d:(%d,%d)\n",counter++,i/num,i%num);
free (help);
getch();
return 0;
}
void initial(void) /*初始化或用于还原*/
{
int i,j;
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++)
matrix[i][j].st=0;
}
void tackle(int i) /*函数用于处理该位置和它上下左右的变化*/
{
matrix[i/num][i%num].st=1-matrix[i/num][i%num].st;
if(i/num<num-1)
matrix[i/num+1][i%num].st=1-matrix[i/num+1][i%num].st;
if(i/num>0)
matrix[i/num-1][i%num].st=1-matrix[i/num-1][i%num].st;
if(i%num<num-1)
matrix[i/num][i%num+1].st=1-matrix[i/num][i%num+1].st;
if(i%num>0)
matrix[i/num][i%num-1].st=1-matrix[i/num][i%num-1].st;
}
int check(void) /*函数用于检查程序是否已经算出结果。*/
{
int i,j;
for(i=0;i<num;i++)
for(j=0;j<num;j++)
if(matrix[i][j].st==0)
return 1;
return 0;
}
下面的程序用于检验上面的结果:
#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
typedef struct
{
unsigned int op:1;
unsigned int st:1;
unsigned int :6;
}BOOL;
int check(BOOL **,int);
int main()
{
int num,i,j,op1,op2;
BOOL **matrix=NULL;
puts("Enter a number:");
scanf("%d",&num);
matrix=(BOOL **)malloc(sizeof(BOOL)*num*num);
if(matrix==NULL)
exit(0);
for(i=0;i<num;i++)
for(j=0;j<num;j++)
matrix[i][j].op=matrix[i][j].st=0;
while(check(matrix,num))
{
for(i=0;i<num;i++)
{
for(j=0;j<num;j++)
printf("%3d",matrix[i][j].st);
printf("\n");
}
printf("\n");
scanf("%d%*c%d",&op1,&op2);
fflush(stdin);
matrix[op1][op2].st=1-matrix[op1][op2].st;
if(op2>0)
matrix[op1][op2-1].st=1-matrix[op1][op2-1].st;
if(op1<num-1)
matrix[op1+1][op2].st=1-matrix[op1+1][op2].st;
if(op1>0)
matrix[op1-1][op2].st=1-matrix[op1-1][op2].st;
if(op2<num-1)
matrix[op1][op2+1].st=1-matrix[op1][op2+1].st;
}
puts("You are excellent!\n");
free(matrix);
getch();
}
int check(BOOL **matrix,int num)
{
int i,j;
for(i=0;i<num;i++)
for(j=0;j<num;j++)
if(matrix[i][j].st==0)
return 1;
return 0;
}
上面的程序并没有把全部可能的结果都算出来,当然要算出来再比较,找出一个最少的步数还是比较简单的,程序问题的关键不在这,程序最大的问题是效率太低,算5*5时大约需要10秒,算6*6就得等好一会,至于更大的数那就只能望洋兴叹了,所以本题重在讨论算法,欢迎大家一起讨论,多给些意见。