关灯游戏

这篇博客探讨了一个5x6灯泡矩阵的游戏,其中每次操作会改变目标灯泡及其相邻灯泡的状态。游戏的目标是通过一系列操作关闭所有灯泡。文章介绍了如何将问题转化为向量和矩阵运算,利用高斯消元法在二阶有限域上求解,并提供了C语言实现的程序。此外,还讨论了解的存在性和唯一性,并提到了与扫雷算法的相似之处。
摘要由CSDN通过智能技术生成

例子:  

有一个5*6的灯泡构成的矩阵,灯的开关规则是这样:当改变某盏灯的,状态时,这盏灯的上下左右相邻的灯的状态也随之改变。例如:
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0

当按下2行3列的开关时,状态变为:
0 1 0 0 1 0
1 1 1 0 1 1
0 0 0 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0

游戏的目的是对于任意给定的亮灭初始态,通过一系列动作关闭所有的灯。
可以注意到的是:
1.矩阵的状态与按开关的顺序无关
2.如果某个开关按下了两次,那么就相当于取消了第一次的操作,也就是说没有开关需要按超过1次

现在问题是:对于给定的初始状态,求出需要按哪些开关来完成游戏

原题在这里
http://acm.pku.edu.cn/JudgeOnline/showproblem?problem_id=1222


把上面的矩阵看成一个m*n的向量X=(x1,x2,...,x(m*n))
对于位置k上的开关,它将变化最多5个位置的开关,对应一个向量
C(k)=(0,0,...,1,0,....,1,...,0)
其中开关状态改变的位置为1,开关状态不改变的位置为0
对于初始向量X=(x1,x2,...,x(m*n)),使用了开关C(k)后,状态会变成
X+C(k) (mod 2)

所以对初始向量X,我们需要选择一系列的k1,k2,...,ks使得
X+C(k1)+C(k2)+....+C(ks) (mod 2)=O=(0,0,0,...,0)
我们可以同样构造一个0,1向量Y,使得,如果位置k出现在k1,k2,...ks中,那么Y
在位置k的值是1,不然是0,这样,我们就可以将上面公式写成矩阵形式
X+Y*C (mod 2)=O
其中C=(C(1)' C(2)' .... C(m*n)')'
也就是C是由这m*n个行向量构成的矩阵,第k行就是向量C(k)
在二阶域上,加和减是相同的,也就是上面的方程等价于
Y*C (mod 2)=X
其中C,X已知,求Y.
由于(mod 2)运算是一个域 (关于乘除加减封闭,加减是mod 2加减,还满足结合率,交换率)
所以我们可以直接在二阶域上用高斯消元法求解(注意加减是mod 2的,对应计算机上的异或运算)
其中,如果C可逆,解是唯一的,如果C不可逆,解可能不存在,也可能不唯一。而如果解不唯一时,

这时解德数目同C的秩有关系,比较有意思的是,如果我们记f(n,2x)是n次第二类切皮雪夫多项式,

那么gcd(f(m,x)(mod 2),f(n,1-x)(mod 2))的次数就是C的自由度(也就是矩阵的阶数减去秩)。

具体证明可以在百度贴吧中内容

而这里C是一个分块三对角阵,我们可以使用追逐法求解,时间复杂度可以只有O(n^3).比较有意思的是这里的分析

同另外一个扫雷的算法问题几乎完全相同,区别是那里在普通的数域,而这里在二阶有限域上。

下面贴出的程序的时间复杂度为O(n^4),这是因为其中同稀疏矩阵的乘法没有优化.

源代码和预编译的代码可以在
     http://download.csdn.net/source/3275909
下载
/*The code to turn off all bulbs in a matrix of bulbs
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef char ** MATRIX;
typedef char * VECTOR;
typedef char *const* CONST_MATRIX;
typedef const char * CONST_VECTOR;

MATRIX matrix_alloc2(int n, int m){
 MATRIX x= (MATRIX)malloc(sizeof(char *)*n+sizeof(char)*n*m);
 int i;
 x[0]=(char *)(x+n);
 for(i=1;i<n;i++)x[i]=x[i-1]+m;
 return x;
}

int maxtrix_count_one(MATRIX x,int n, int m){
 int r=0;
 int i,j;
 for(i=0;i<n;i++)for(j=0;j<n;j++)if(x[i][j]!=0)r++;
 return r;
}

MATRIX matrix_alloc(int n){
    MATRIX x = (MATRIX)malloc(sizeof(char *)*n+sizeof(char)*n*n);
    int i;
    x[0]=(char *)(x+n);
    for(i=1;i<n;i++)x[i]=x[i-1]+n;
    return x;
}

void matrix_free(MATRIX x){
    free(x);
}

VECTOR vector_alloc(int n){
    VECTOR x = (VECTOR)malloc(sizeof(char)*n);
    return x;
}

void vector_free(VECTOR x){
    free(x);
}

void matrix_sum(MATRIX A, CONST_MATRIX B, int n){
    int i,j;
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            A[i][j] ^= B[i][j];
        }
    }
}

void vector_sum(VECTOR a, CONST_VECTOR b, int n){
    int i;
    for(i=0;i<n;i++)a[i]^=b[i];
}

void matrix_mul(MATRIX out, CONST_MATRIX in1, CONST_MATRIX in2, int n){
    int i,j,k;
    for(i=0;i<n;i++)for(j=0;j<n;j++){
        int sum=0;
        for(k=0;k<n;k++){
            if(in1[i][k])
                sum^=in2[k][j];
        }
        out[i][j]=sum;
    }
}

void matrix_mul_H(MATRIX out, CONST_MATRIX in, int n){
    int i,j;
    for(i=0;i<n;i++)for(j=0;j<n;j++){
        int sum=in[i][j];
        if(i>0)sum^=in[i-1][j];
        if(i<n-1)sum^=in[i+1][j];
        out[i][j]=sum;
    }
}

void matrix_mul_vector(VECTOR out, CONST_MATRIX m, CONST_VECTOR in, int n){
    int i,j;
    for(i=0;i<n;i++){
        int sum=0;
        for(j=0;j<n;j++){
            sum^=m[i][j]&in[j];
        }
        out[i]=sum;
    }
}

void H_mul_vector(VECTOR out, CONST_VECTOR in, int n){
    int i;
    for(i=0;i<n;i++){
        int sum=in[i];
        if(i>0)sum^=in[i-1];
        if(i<n-1)sum^=in[i+1];
        out[i]=sum;
    }
}

void vector_init_const(VECTOR v, char c, int n){
    int i;
    for(i=0;i<n;i++)v[i]=c;
}

void matrix_init_O(MATRIX o, int n){
    int i,j;
    for(i=0;i<n;i++)for(j=0;j<n

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值