java算法点灯_点灯游戏算法

1 0 1 0 0 1

1 1 0 1 0 1

0 0 1 0 1 1

1 0 0 1 0 0

0 1 0 0 0 0

这是一个很有趣的游戏,可能很多人都玩过。每一次玩的时候都是要不断地进行尝试,我们人的大脑或许可以在特定的情况下得到比较准确地判断。但是要是这个问题交给计算机去完成的话,它可能就只能老老实实地去搜索了。如果完全暴力的搜索的话,假设矩阵式N*M的话时间复杂度是2^N*M,显然是很大的。算法实现不难但是这种方法还是很有限的。

通过研究这个游戏我们可以得到几个规律:

1,若存在一个可行解使得最后所有灯的状态都是熄灭的话,这些操作的顺序不会影响最后的结果。所以我们最后可以用一个bool矩阵表示解。

2,每一个灯至多只需要进行一次操作(熄灭或者点亮),因为偶数次操作和不操作是等价的,而基数次操作和操作一次是等价的。

我们从另一个角度去思考,如果第一行的操作已经决定的情况下

为了保证所有灯的状态保持是灭的话,第二行的操作就可以根据第一行来确定,第三行可以根据第二行来确定。只要最后恰好所有灯都灭了的话,就是我们所要找的解。所以我们只要枚举第一行的所有情况,然后根据第一行的结果推出后面所有的操作,最后判断是否为可行解就行了。这一下,时间复杂度变成了2^N.在本题的规模情况下还是能很快的解决的。算法实现的代码如下:

#include

int l[7] , a[7][7] ,t[7][7] , b[7][7]

;//l是记录第一行的排列组合情况

int f = 0 , n = 5 , m = 6 ;

void cpy(){//每一次搜索前将原数组a

copy到temp数组

for(int i = 1 ; i <= n ;

i++)

for(int j = 1 ; j <= m ;

j++)

t[i][j] = a[i][j] ;

}

int ok(int i ,int

j){//判断下表是否越界

if(i >=1

&& i <=n

&& j >= 1

&& j

<=m)

return 1 ;

else return 0 ;

}

void mark(int i , int

j){//点灯的操作

t[i][j] = ! t[i][j] ;

if(ok(i-1 , j)) t[i-1][j] = ! t[i-1][j]

;

if(ok(i+1 , j)) t[i+1][j] = ! t[i+1][j]

;

if(ok(i , j-1)) t[i][j-1] = ! t[i][j-1]

;

if(ok(i , j+1)) t[i][j+1] = ! t[i][j+1]

;

}

void dis(int

ta[7][7]){//打印一个数组的内容

for(int i = 1 ; i <= n ;

i++)

{

for(int j = 1 ; j <= m;

j++)

{

if(j != 1)

printf(" ")

;

printf("%d" , ta[i][j]) ;

}

printf("\n") ;

}

}

int

af(){//判断操作完成后结果是否为全部为0(事实上只判断最后一行因为之前我  //们的操作已经保证都为0了)的函数

for(int i = 1 ; i <= m ;

i++)

if(t[n][i]) return 0 ;

return 1 ;

}

void sear(){//搜索的函数

for(int i = 1 ; i <= m ;

i++)

{

if(l[i])

mark(1 , i) ;

b[1][i] = l[i] ;

}

for(int i = 2 ; i <= n ;

i++)

for(int j = 1 ; j <= m ;

j++)

if(t[i-1][j])  mark(i , j) ,

b[i][j] = 1 ;

else b[i][j] = 0 ;

}

int ml(int cur){//生成组合

if(f)

return 1 ;

if(cur == m + 1)

{

cpy() ;

sear() ;

if(af()) f = 1 ;

}

else

for(int i = 0 ; i < 2 ;

i++)

l[cur] = i , ml( cur + 1 ) ;

return 1 ;

}

int main(){

for(int i = 1 ; i <= n ;

i++)

for(int j = 1 ; j <= m ;

j++)

scanf("%d" , &a[i][j])

;

if(ml(1)) dis(b) ;

return 0 ;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值