需求说明:
在一个正方体内,有平方个方格相邻排列,每个方格里面有一个开关,每个开关按下的时候,会翻转相邻四个格子和它自己格子灯的亮灭,已知条件为正方形的尺寸,求哪些开关按下才能保证所有区域的灯都被点亮。
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
控灯问题
最新推荐文章于 2021-06-26 17:17:46 发布