码迷,mamicode.com
首页 > 其他好文 > 详细

编程题-翻棋游戏-枚举

时间:2015-03-08 17:13:10      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:编程题   枚举   poj-3279   

题目

 约翰知道,那些高智力又快乐的奶牛产奶量特别高.所以他做了一个翻瓦片的益智游戏来娱乐奶牛.在一个M×N(1≤M,N≤15)的骨架上,每一个格子里都有一个可以翻转的瓦片.瓦片的一面是黑色的,而另一面是白色的.对一个瓦片进行翻转,可以使黑变白,也可以使白变黑.然而,奶牛们的蹄子是如此的巨大而且笨拙,所以她们翻转一个瓦片的时候,与之有公共边的相邻瓦片也都被翻转了.那么,这些奶牛们最少需要多少次翻转,使所有的瓦片都变成白面向上呢?如杲可以做到,输出字典序最小的结果(将结果当成字符串处理).如果不能做到,输出“IMPOSSIBLE”.

样例

输入
M=4
N=4
每个格子的颜色如下(0表示白色,1表示黑色)
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1

输出:
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0

题目分析

首先,一个格子的连续翻转2次的,颜色会恢复原状,并且一个格子的颜色变换取决于他周围和他自身,那么可以知道,
1.一个棋子要么翻或者不翻,不会存在一个棋子翻2次及其以上
2.给定一个解法,翻棋子的顺序是无关紧要的

如果我们用枚举的方法,枚举出每一行的翻法,复杂度为O(2MN)

但是我们发现,只要枚举出第一行的所有翻法,那么第二行的翻法是确定的(就是保证第一行的中所有是黑色的格子,则必须翻转对应的下一行格子(如果这样,那么第一行就不能满足条件)
这样,给出了前一行的翻法,那么他一下行的翻法也就固定了,这样只要判断最后一行是否全是白色,就可以判断这个解法是不是正确的,这样的话,复杂度就降低为O(MN2N)

python代码

已样例作为输入
我们输出了所有的解法,已验证我们算法是不是正确的,并在最后打印最优解

import copy

#m*n 
a=[
   [1,0,0,1],
   [0,1,1,0],
   [0,1,1,0],
   [1,0,0,1]
   ]

m=4
n=4
#保存最小步数以及对应到解
m_step=m*n
min_solve=list()

#打印一个解
def print_solve(ans):
    for i in ans:
        print i
    print ‘------------------------‘

#对于第一行到翻转方法,有没有对应到解,
#x到位代表当前到第一行到翻法
#比如x=5 2进制表示为(只取最后4位) .... 0101  1在到位置表示要翻,这里意思是翻第二个和第四个
#(注意:程序由于方便,其实是把2进制到顺序反向排列到,比如上面,其实反序后是 1010 ....表示翻第一个和第三个)
def check(x):
    tmp=copy.deepcopy(a)
    ans=[[0]*n for t in range(m)]
    step=0;
    for i in range(m):
        if x & 1<<i:
            ans[0][i]=1
            step+=1
            #翻转自身和周围
            tmp[0][i]^=1
            if m > 1:
                tmp[1][i]^=1
            if i>0:
                tmp[0][i-1]^=1
            if i<n-1:
                tmp[0][i+1]^=1
    for i in range(1,m):
        for j in range(0,n):
            if tmp[i-1][j]==1:
                ans[i][j]=1
                step+=1
                #翻转自身和周围
                tmp[i-1][j]^=1
                tmp[i][j]^=1
                if i < m-1:
                    tmp[i+1][j]^=1
                if j>0:
                    tmp[i][j-1]^=1
                if j<n-1:
                    tmp[i][j+1]^=1
    #如果最后一行存在1,则表示当前第一行到翻法是无解
    for i in range(n):
        if tmp[m-1][i]==1:
            return False

    print_solve(ans)
    global m_step,min_solve
    if m_step > step:
        m_step=step
        min_solve=ans
    return True

solve_num=0;
for x in range(1<<n):         
    if check(x):
        solve_num+=1


if solve_num==0:
    print "impossible"
else:
    print "min step is %d" % m_step
    print_solve(min_solve)


输出:

[0, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 0, 1]
[0, 0, 0, 0]
------------------------
[1, 0, 0, 0]
[0, 1, 0, 1]
[0, 0, 1, 1]
[0, 1, 1, 1]
------------------------
[0, 1, 0, 0]
[0, 1, 1, 1]
[1, 0, 0, 0]
[1, 1, 0, 1]
------------------------
[1, 1, 0, 0]
[1, 0, 1, 1]
[0, 0, 1, 0]
[1, 0, 1, 0]
------------------------
[0, 0, 1, 0]
[1, 1, 1, 0]
[0, 0, 0, 1]
[1, 0, 1, 1]
------------------------
[1, 0, 1, 0]
[0, 0, 1, 0]
[1, 0, 1, 1]
[1, 1, 0, 0]
------------------------
[0, 1, 1, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 1, 1, 0]
------------------------
[1, 1, 1, 0]
[1, 1, 0, 0]
[1, 0, 1, 0]
[0, 0, 0, 1]
------------------------
[0, 0, 0, 1]
[1, 0, 1, 0]
[1, 1, 0, 0]
[1, 1, 1, 0]
------------------------
[1, 0, 0, 1]
[0, 1, 1, 0]
[0, 1, 1, 0]
[1, 0, 0, 1]
------------------------
[0, 1, 0, 1]
[0, 1, 0, 0]
[1, 1, 0, 1]
[0, 0, 1, 1]
------------------------
[1, 1, 0, 1]
[1, 0, 0, 0]
[0, 1, 1, 1]
[0, 1, 0, 0]
------------------------
[0, 0, 1, 1]
[1, 1, 0, 1]
[0, 1, 0, 0]
[0, 1, 0, 1]
------------------------
[1, 0, 1, 1]
[0, 0, 0, 1]
[1, 1, 1, 0]
[0, 0, 1, 0]
------------------------
[0, 1, 1, 1]
[0, 0, 1, 1]
[0, 1, 0, 1]
[1, 0, 0, 0]
------------------------
1
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
------------------------
min step is 4
[0, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 0, 1]
[0, 0, 0, 0]
------------------------

编程题-翻棋游戏-枚举

标签:编程题   枚举   poj-3279   

原文地址:http://blog.csdn.net/lizo_is_me/article/details/44134019

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!