控灯问题



需求说明:
在一个正方体内,有平方个方格相邻排列,每个方格里面有一个开关,每个开关按下的时候,会翻转相邻四个格子和它自己格子灯的亮灭,已知条件为正方形的尺寸,求哪些开关按下才能保证所有区域的灯都被点亮。






void CAnswer::OnPaint()
{
    CPaintDC dc(this); // device context for painting


    int i,j,k=0;
    for(i=0; i<m_nDemtion; i++)
    {
        for(j=0; j<m_nDemtion; j++)
        {
            dc.TextOut(j*20+5, i*20+5, *(m_pMartix+i*m_nDemtion+j) ? "1":"0");
        }
    }


    if(m_pAns == NULL) return;
    for(i=0; i<m_nDemtion; i++)
    {
        if(i*i < m_nDemtion)
        {
            dc.TextOut(i*20+5, j*20+105, *(m_pAns+i) ? "1":"0");
            continue;
        }
        for(j=1; j<i; j++)
        {
            for(k=0;k<i;k++)
            {
                dc.TextOut(k*20+5, j*20+105, *(m_pAns+j*m_nDemtion+k) ? "1":"0");
            }
        }
        i = m_nDemtion;
    }
}


void CAnswer::SetDim(int n)
{
    if(n<=0) return;


    m_nDemtion = n*n;
    if(m_pMartix)
    {
        delete[] m_pMartix;
        m_pMartix = NULL;
    }
    m_pMartix = new int[m_nDemtion*m_nDemtion];
    int i,j,k;
    memset(m_pMartix, 0, m_nDemtion*m_nDemtion*sizeof(int));
    for(i=0; i<n; i++) //y 
    {
        for(k=0; k<n; k++) //x
        {
            for(j=max(0,k-1); j<min(n,k+2); j++)
            {
                *(m_pMartix+(k+i*n)*m_nDemtion+n*i+j)= 1;
            }
            if(i>0)
            {
                *(m_pMartix+(k+i*n)*m_nDemtion+n*i-n+k)= 1;
            }
            if(i<n-1)
            {
                *(m_pMartix+(k+i*n)*m_nDemtion+n*i+n+k)= 1;
            }
        }
    }
}


void CAnswer::OnFind()
{
    Find();
    Invalidate();
}


int * CAnswer::Find()
{
    if(m_nDemtion <= 0) return NULL;


    int    *pAns = new int[m_nDemtion*m_nDemtion];
    int    *pTmp = new int[m_nDemtion];


    int i,j,k,l;
    memset(pAns, 0, m_nDemtion*m_nDemtion*sizeof(int));


    for(i=0; i<m_nDemtion; i++)
    {
        *(pAns+i*(m_nDemtion+1)) = 1;
    }


    for(i=0; i<m_nDemtion; i++)
    {
        for(j=i; j<m_nDemtion; j++)
        {
            if(*(m_pMartix+j*m_nDemtion+i)) break;
        }
        //        TRACE("i:%d, j:%d\n", i,j);
        //j,i调换
        if(i < j)
        {
            if(j>=m_nDemtion) continue;


            memcpy(pTmp, m_pMartix+j*m_nDemtion, m_nDemtion*sizeof(int));
            memcpy(m_pMartix+j*m_nDemtion, m_pMartix+i*m_nDemtion, m_nDemtion*sizeof(int));
            memcpy(m_pMartix+i*m_nDemtion, pTmp, m_nDemtion*sizeof(int));


            memcpy(pTmp, pAns+j*m_nDemtion, m_nDemtion*sizeof(int));
            memcpy(pAns+j*m_nDemtion, pAns+i*m_nDemtion, m_nDemtion*sizeof(int));
            memcpy(pAns+i*m_nDemtion, pTmp, m_nDemtion*sizeof(int));
            j = i;
        }


        for(k=0; k<m_nDemtion; k++)
        {
            if(i==k) continue;
            if(*(m_pMartix+k*m_nDemtion+i) == 0)  continue;


            // k行与j行做加和,再归一化
            for(l=0; l<m_nDemtion; l++)
            {
                *(m_pMartix+k*m_nDemtion+l) = (*(m_pMartix+j*m_nDemtion+l) + *(m_pMartix+k*m_nDemtion+l)) & 1;
                *(pAns+k*m_nDemtion+l) = (*(pAns+j*(m_nDemtion)+l) + *(pAns+k*(m_nDemtion)+l)) & 1;
            }
        }
    }


    memcpy(m_pMartix, pAns, m_nDemtion*m_nDemtion*sizeof(int));
    delete[] pAns;


    for(i=0; i<m_nDemtion; i++)
    {
        *(pTmp+i) = 0;
        for(j=0; j<m_nDemtion; j++)
        {
            *(pTmp+i) += *(m_pMartix+i*m_nDemtion+j);
        }
        *(pTmp+i) &= 1;
    }


    if(m_pAns) delete [] m_pAns;
    m_pAns =  pTmp;
    return m_pAns;
}




算法总结:
本算法的核心是布尔矩阵方程的求解,A*B=C
A为控制行向量,B为规则矩阵,C为结果,与A尺寸相同,欲求为A
则A=C*B^(-1)
比如尺寸为3的方形;
那么A为9*1,B为9*9,C为9*1
在进行矩阵运算时,如求B的逆矩阵时,充分利用开关的二值规则,即所有中间过程的整数计算的结果在输出时与1与,也就是取最低一位,就可以满足题目要求。
规则数学表达如下:
0+0=0
0+1=1
1+1=0
0-0=0
1-1=0
1-0=1
0-1=1
1*0=0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值