关灯游戏,如果是灯全亮时,有个解。其解为
01101
01110
00111
11011
11000
进行旋转后,可以得到其它的三个解,共四个解。
这四个解,两两组合,可以得到三个不同的结果,记作 T1,T2,T3。
它们可用于得到某种局面的其它解。
比如,对于局面 F
11100
10100
11000
10001
11011
其解为 R
00111
10110
00010
01001
01100
R+T1 就相当于,在 R 的基础上,先将灯全部打开,再全部关闭。得到的值就是 F 的另外一个解。所以,每个局面,都有四个解:
R
R+T1
R+T2
R+T3
比如:
m_field
11100
10100
11000
10001
11011
找到解
m_recorder
00111
10110
00010
01001
01100
解2
10010
00011
00010
11100
11001
解3
01001
00011
11001
11100
00010
解4
11100
10110
11001
01001
10111
01101
01110
00111
11011
11000
进行旋转后,可以得到其它的三个解,共四个解。
这四个解,两两组合,可以得到三个不同的结果,记作 T1,T2,T3。
它们可用于得到某种局面的其它解。
比如,对于局面 F
11100
10100
11000
10001
11011
其解为 R
00111
10110
00010
01001
01100
R+T1 就相当于,在 R 的基础上,先将灯全部打开,再全部关闭。得到的值就是 F 的另外一个解。所以,每个局面,都有四个解:
R
R+T1
R+T2
R+T3
比如:
m_field
11100
10100
11000
10001
11011
找到解
m_recorder
00111
10110
00010
01001
01100
解2
10010
00011
00010
11100
11001
解3
01001
00011
11001
11100
00010
解4
11100
10110
11001
01001
10111
public class LightsOff {
// #pragma once
class CField {
// public
// CField()
// : m_iWidth(0)
// , m_iHeight(0)
// {
// memset(m_ivField, 0, sizeof(m_ivField));
// }
// ~CField()
// {
// }
public CField() {
// m_iWidth = 5;
// m_iHeight = 5;
Create(5, 5);
}
public CField(int w, int h) {
// m_iWidth = w;
// m_iHeight = h;
Create(w, h);
}
public CField(CField fld) {
m_iWidth = fld.m_iWidth;
m_iHeight = fld.m_iHeight;
// memcpy(m_ivField, fld.m_ivField, sizeof(m_ivField));
memcpy(m_ivField, fld);
// for(int i=0; i<fld.m_ivField.length; i++)
// {
// m_ivField[i] = fld.m_ivField[i];
// }
}
// protected:
// // 空间最大32*32
// __int32 m_ivField[32];
protected int[] m_ivField = new int[32];
// 宽度
int m_iWidth;
// 高度
int m_iHeight;
// public:
// 创建
public void Create(int iWidth, int iHeight) {
if (iWidth < 1) {
iWidth = 1;
} else if (iWidth > 32) {
iWidth = 32;
}
if (iHeight < 1) {
iHeight = 1;
} else if (iHeight > 32) {
iHeight = 32;
}
m_iWidth = iWidth;
m_iHeight = iHeight;
Clear();
}
// 清空
public void Clear() {
// memset(m_ivField, 0, sizeof(m_ivField));
for (int i = 0; i < m_ivField.length; i++) {
m_ivField[i] = 0;
}
}
// 取得宽度
public int Width() {
return m_iWidth;
}
// 取得高度
public int Height() {
return m_iHeight;
}
// 是否亮灯
public boolean IsLightOn(int x, int y) {
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
return (m_ivField[y] & mask) != 0;
}
return false;
}
public void SetLight(int x, int y) {
SetLight(x, y, 2);
}
// 设置灯 type:0关灯,1开灯, 否则把开的灯关掉,关的灯开启
public void SetLight(int x, int y, int type) {
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
if (type == 0) {
m_ivField[y] &= ~mask;
} else if (type == 1) {
m_ivField[y] |= mask;
} else {
m_ivField[y] ^= mask;
}
}
}
// 是否亮灯
public boolean IsLightOn(int index) {
int x = index % m_iWidth;
int y = index / m_iWidth;
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
return (m_ivField[y] & mask) != 0;
}
return false;
}
public void SetLightI(int index) {
SetLightI(index, 2);
}
// 设置灯 type:0关灯,1开灯, 否则把开的灯关掉,关的灯开启
public void SetLightI(int index, int type) {
int x = index % m_iWidth;
int y = index / m_iWidth;
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
if (type == 0) {
m_ivField[y] &= ~mask;
} else if (type == 1) {
m_ivField[y] |= mask;
} else {
m_ivField[y] ^= mask;
}
}
}
// 关灯
void LightsOff(int x, int y) {
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
if (y > 0) {
m_ivField[y - 1] ^= mask;
}
if (y < m_iHeight - 1) {
m_ivField[y + 1] ^= mask;
}
mask = 7;
if (x == 0) {
mask >>= 1;
} else {
mask <<= (x - 1);
}
m_ivField[y] ^= (mask & ~(-1 << m_iWidth));
}
}
// 关灯
void LightsOff(int index) {
int x = index % m_iWidth;
int y = index / m_iWidth;
if (x >= 0 && x < m_iWidth && y >= 0 && y < m_iHeight) {
int mask;
mask = 1;
mask <<= x;
if (y > 0) {
m_ivField[y - 1] ^= mask;
}
if (y < m_iHeight - 1) {
m_ivField[y + 1] ^= mask;
}
mask = 7;
if (x == 0) {
mask >>= 1;
} else {
mask <<= (x - 1);
}
m_ivField[y] ^= (mask & ~(-1 << m_iWidth));
}
}
// 绘制
// void Paint(CDC * pDC, int x0, int y0, int uw = 10, int type = 0)
// {
// // 绘制底色
// if(type == 0)
// {
// pDC->FillSolidRect(x0, y0, uw * m_iWidth, uw * m_iHeight, RGB(50, 50,
// 50));
// }
// // 绘制灯
// int x, y;
// __int32 mask = 1;
// for(x = 0; x < m_iWidth; x++)
// {
// for(y = 0; y < m_iHeight; y++)
// {
// if(m_ivField[y] & mask)
// {
// if(type == 0)
// {
// pDC->FillSolidRect(
// x0 + x * uw, y0 + y * uw,
// uw, uw, RGB(0, 200, 0));
// }
// else if(type == 1)
// {
// pDC->Ellipse(
// x0 + x * uw + uw / 3, y0 + y * uw + uw / 3,
// x0 + x * uw + uw - uw / 3, y0 + y * uw + uw - uw / 3);
// }
// else
// {
// pDC->FillSolidRect(
// x0 + x * uw, y0 + y * uw,
// uw, uw, RGB(255, 255, 255));
// }
// }
// }
// mask <<= 1;
// }
// if(type == 0)
// {
// // 绘制网格
// for(x = 0; x <= m_iWidth; x++)
// {
// pDC->FillSolidRect(
// x0 + x * uw, y0,
// 1, uw * m_iHeight, RGB(255, 255, 255));
// }
// for(y = 0; y <= m_iHeight; y++)
// {
// pDC->FillSolidRect(
// x0, y0 + y * uw,
// uw * m_iWidth, 1, RGB(255, 255, 255));
// }
// }
// }
// CField & operator = (CField & fld)
public CField opSet(CField fld) {
m_iWidth = fld.m_iWidth;
m_iHeight = fld.m_iHeight;
// memcpy(m_ivField, fld.m_ivField, sizeof(m_ivField));
memcpy(m_ivField, fld);
return fld;
}
public void memcpy(int[] des, CField fld) {
for (int i = 0; i < fld.m_ivField.length; i++) {
m_ivField[i] = fld.m_ivField[i];
}
}
public boolean memcmp(int[] des, CField fld) {
for (int i = 0; i < fld.m_ivField.length; i++) {
if (m_ivField[i] != fld.m_ivField[i])
return false;
}
return true;
}
// bool operator == (CField & fld)
public boolean opEq(CField fld) {
if (m_iWidth == fld.m_iWidth && m_iHeight == fld.m_iHeight &&
// memcmp(m_ivField, fld.m_ivField, sizeof(m_ivField)) == 0)
memcmp(m_ivField, fld)) {
return true;
}
return false;
}
// CField & operator += (CField & fld)
// {
// int y;
// for(y = 0; y < m_iHeight; y++)
// {
// m_ivField[y] ^= fld.m_ivField[y];
// }
// return *this;
// }
CField opAdd(CField fld) {
int y;
for (y = 0; y < m_iHeight; y++) {
m_ivField[y] ^= fld.m_ivField[y];
}
return this;
}
// CField & AndNot(CField & fld)
CField AndNot(CField fld) {
int y;
for (y = 0; y < m_iHeight; y++) {
m_ivField[y] &= ~fld.m_ivField[y];
}
return this;
}
// bool operator *(CField &fld)
boolean opMul(CField fld) {
int tmp;
int x, y;
boolean re = false;
int mask;
for (y = 0; y < m_iHeight; y++) {
tmp = m_ivField[y];
tmp &= fld.m_ivField[y];
mask = 1;
for (x = 0; x < m_iWidth; x++, mask <<= 1) {
if ((tmp & mask) != 0) {
re = !re;
}
}
}
return re;
}
// 打印
// void Print(FILE * fp)
void fprintf(String s) {
System.out.print(s);
}
void fprintf(String format, Object obj) {
if (format.equals("%c")) {
System.out.print(obj);
} else {
System.out.print(format + obj);
}
}
/**
* 矩阵顺时针旋转 90 度
* @return
*/
public CField rotate()
{
CField fld = new CField();
int x, y;
for (x = 0; x < m_iWidth; x++) {
for (y = 0; y < m_iHeight; y++) {
if( IsLightOn(x, y))
{
//System.out.println("359 x:" + x + " y:" + y);
fld.SetLight(m_iWidth-y-1, x, 1);
}
}
}
return fld;
}
void Print(String title) {
//fprintf(title);
System.out.println(title);
Print();
}
void Print() {
int x, y;
int mask;
for (y = 0; y < m_iHeight; y++) {
mask = 1;
for (x = 0; x < m_iWidth; x++, mask <<= 1) {
fprintf("%c", ((m_ivField[y] & mask) != 0) ? '1' : '0');
}
fprintf("\n");
}
fprintf("\n");
}
// void PrintInt() {
// int x, y;
// int mask;
// for (y = 0; y < m_iHeight; y++) {
// fprintf(Integer.toBinaryString(m_ivField[y]) + " ");
// // mask = 1;
// // for(x = 0; x < m_iWidth; x++, mask <<= 1)
// // {
// // //fprintf( "%c", ((m_ivField[y] & mask)!=0) ? '1' : '0');
// // }
// fprintf("\n");
// }
// fprintf("\n");
// }
}
class CMatrix extends CField {
// public:
// CMatrix()
// : m_matrix(NULL)
// {
// }
// ~CMatrix()
// {
// Destroy();
// }
// 矩阵
protected CField[] m_matrix;
// public:
// // 销毁矩阵
// void Destroy()
// {
// if(m_matrix)
// {
// delete []m_matrix;
// m_matrix = NULL;
// }
// m_iWidth = 0;
// m_iHeight = 0;
// }
// 创建矩阵(iWidth, iHeight只是用来初始化CField向量用的)
public void Create(int iWidth, int iHeight) {
// Destroy();
if (iWidth < 1) {
iWidth = 1;
} else if (iWidth > 32) {
iWidth = 32;
}
if (iHeight < 1) {
iHeight = 1;
} else if (iHeight > 32) {
iHeight = 32;
}
m_iWidth = iWidth;
m_iHeight = iHeight;
Clear();
int n = m_iWidth * m_iHeight;
m_matrix = new CField[n];
int i = 0;
for (i = 0; i < n; i++) {
m_matrix[i] = new CField(m_iWidth, m_iHeight);
// m_matrix[i].Create(m_iWidth, m_iHeight);
}
}
// 置为单位矩阵
void SetAsI() {
int n = m_iWidth * m_iHeight;
int i = 0;
for (i = 0; i < n; i++) {
m_matrix[i].Clear();
m_matrix[i].SetLightI(i, 1);
}
}
// 置为关灯矩阵
public void SetAsL(CField mask) {
int n = m_iWidth * m_iHeight;
int i = 0;
for (i = 0; i < n; i++) {
m_matrix[i].Clear();
if (mask.IsLightOn(i) == false) {
m_matrix[i].LightsOff(i);
m_matrix[i].AndNot(mask);
}
}
}
// 打印矩阵
public void Print() {
int x, y;
int n = m_iWidth * m_iHeight;
for (y = 0; y < n; y++) {
for (x = 0; x < n; x++) {
fprintf("%c", m_matrix[y].IsLightOn(x) ? '1' : '0');
}
fprintf("\n");
}
fprintf("\n");
}
// 计算逆矩阵
boolean Inverse_debug(CMatrix I) {
System.out.println("470 Inverse(CMatrix I) m_switch");
Print();
CField fldTmp;
I.Create(m_iWidth, m_iHeight);
I.SetAsI();
System.out.println("476 I");
I.Print();
int i, j;
int n = m_iWidth * m_iHeight;
boolean succ = true;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
if (m_matrix[j].IsLightOn(i)) {
break;
}
}
System.out.println("485 i:" + i + " j:" + j);
if (j == n) {
succ = false;
} else {
if (j != i) {
// 交换行
System.out.println("交换行");
System.out.println("499 m_switch");
Print();
fldTmp = m_matrix[j];
m_matrix[j] = m_matrix[i];
m_matrix[i] = fldTmp;
System.out.println("499 m_switch");
Print();
System.out.println("501 I");
I.Print();
fldTmp = I.m_matrix[j];
I.m_matrix[j] = I.m_matrix[i];
I.m_matrix[i] = fldTmp;
System.out.println("501 I");
I.Print();
}
// 以第i行作为主元进行消元
for (j = 0; j < n; j++) {
if (j != i && m_matrix[j].IsLightOn(i)) {
System.out.println("消元");
System.out.println("514 i:" + i + " j:" + j);
// 消元
// m_matrix[j] += m_matrix[i];
System.out.println("515 m_switch");
Print();
m_matrix[j].opAdd(m_matrix[i]);
System.out.println("515 m_switch");
Print();
// I.m_matrix[j] += I.m_matrix[i];
System.out.println("517 I");
I.Print();
I.m_matrix[j].opAdd(I.m_matrix[i]);
System.out.println("517 I");
I.Print();
}
}
}
}
System.out.println("523 end Inverse");
return succ;
}
// 计算逆矩阵
boolean Inverse(CMatrix I) {
CField fldTmp;
I.Create(m_iWidth, m_iHeight);
I.SetAsI();
int i, j;
int n = m_iWidth * m_iHeight;
boolean succ = true;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
if (m_matrix[j].IsLightOn(i)) {
break;
}
}
if (j == n) {
succ = false;
} else {
if (j != i) {
// 交换行
fldTmp = m_matrix[j];
m_matrix[j] = m_matrix[i];
m_matrix[i] = fldTmp;
fldTmp = I.m_matrix[j];
I.m_matrix[j] = I.m_matrix[i];
I.m_matrix[i] = fldTmp;
}
// 以第i行作为主元进行消元
for (j = 0; j < n; j++) {
if (j != i && m_matrix[j].IsLightOn(i)) {
// 消元
// m_matrix[j] += m_matrix[i];
m_matrix[j].opAdd(m_matrix[i]);
// I.m_matrix[j] += I.m_matrix[i];
I.m_matrix[j].opAdd(I.m_matrix[i]);
}
}
}
}
return succ;
}
// CField operator *(CField & fld)
CField opMulM(CField fld) {
CField tmp = new CField(m_iWidth, m_iHeight);
// tmp.Create(m_iWidth, m_iHeight);
int n = m_iWidth * m_iHeight;
int i;
for (i = 0; i < n; i++) {
if (m_matrix[i].opMul(fld)) {
tmp.SetLightI(i);
}
}
return tmp;
}
CField opIdx(int index) {
return m_matrix[index];
}
}
// 设置大小
void SetSize(int iWidth, int iHeight) {
// int iWidth = m_cbWidth.GetCurSel() + 1;
// int iHeight = m_cbHeight.GetCurSel() + 1;
m_field = new CField(iWidth, iHeight);
// m_field.Create(iWidth, iHeight);
m_mask = m_field;
m_recorder = m_field;
int w, h;
int fw = m_iUnitWidth * iWidth;
int fh = m_iUnitWidth * iHeight;
w = fw + 128;
h = fh + 100;
if (w < 360) {
w = 360;
}
if (h < 200) {
h = 200;
}
// MoveWindow(
// (::GetSystemMetrics(SM_CXSCREEN) - w) / 2,
// (::GetSystemMetrics(SM_CYSCREEN) - h) / 2,
// w, h);
// CRect rect;
// GetClientRect(&rect);
// m_iX0 = 50 + (rect.Width() - fw) / 2;
// m_iY0 = 50;
// 计算求解矩阵
m_switch = new CMatrix();
m_switch.Create(iWidth, iHeight);
m_trans = new CMatrix();
m_trans.Create(iWidth, iHeight);
m_trans.SetAsI();
m_switch.SetAsL(m_mask);
m_switch.Inverse(m_trans);
// System.out.println("m_switch");
// m_switch.Print();
m_switch.SetAsL(m_mask);
// System.out.println("m_switch");
// m_switch.Print();
// System.out.println("m_trans");
// m_trans.Print();
// Invalidate();
}
private void solve() {
m_recorder = m_trans.opMulM(m_field);
if (m_switch.opMulM(m_recorder).opEq(m_field)) {
// MessageBox("找到解", "成功", MB_ICONINFORMATION);
System.out.println("找到解");
} else {
// MessageBox("未找到解", "失败", MB_ICONERROR);
System.err.println("未找到解");
m_recorder.Clear();
}
System.out.println("m_recorder");
m_recorder.Print();
// System.out.println("m_recorder.PrintInt();");
// m_recorder.PrintInt();
}
private void inputAllLight() {
for(int i=0; i<5; i++)
{
for(int j=0; j<5; j++)
{
m_field.SetLight(i, j, 2);
}
}
System.out.println("m_field");
m_field.Print();
}
/**
* 输入的数据
*/
private void input() {
//m_field = m_trans.m_matrix[0];
// m_field.SetLight(0, 0, 1);
// m_field.SetLight(0, 1, 1);
// m_field.SetLight(1, 0, 1);
m_field.LightsOff(0, 0);
m_field.LightsOff(1, 0);
// for(int i=0; i<5; i++)
// {
// for(int j=0; j<5; j++)
// {
// m_field.SetLight(i, j, 2);
// }
// }
System.out.println("m_field");
m_field.Print();
}
/**
* 测试求解过程
*/
private static void testSolve()
{
LightsOff lo = new LightsOff();
lo.SetSize(5, 5);
//lo.SetSize(2, 3);
lo.input();
lo.solve();
}
/**
* 打印求逆矩阵的过程
*/
private void debugInverse(int iWidth, int iHeight)
{
m_field = new CField(iWidth, iHeight);
m_mask = m_field;
m_recorder = m_field;
m_switch = new CMatrix();
m_switch.Create(iWidth, iHeight);
m_trans = new CMatrix();
m_trans.Create(iWidth, iHeight);
m_trans.SetAsI();
m_switch.SetAsL(m_mask);
m_switch.Inverse_debug(m_trans);
System.out.println("m_switch");
m_switch.Print();
m_switch.SetAsL(m_mask);
System.out.println("m_switch");
m_switch.Print();
System.out.println("m_trans");
m_trans.Print();
}
private static void testInverse()
{
LightsOff lo = new LightsOff();
lo.debugInverse(3,3);
}
/**
* 测试矩阵旋转
*/
private static void testRotate()
{
LightsOff lo = new LightsOff();
//CField f1 = lo.new CField(5,5);
CField f1 = lo.new CField(5,5);
// f1.LightsOff(0, 0);
// f1.LightsOff(1, 0);
f1.LightsOff(0, 1);
f1.LightsOff(0, 3);
f1.Print("f1");
CField f2 = f1.rotate();
f2.Print("f2");
CField f3 = f2.rotate();
f3.Print("f3");
CField f4 = f3.rotate();
f4.Print("f4");
}
private static void solveAllLight()
{
LightsOff lo = new LightsOff();
solveAllLight(lo);
}
/**
* 求解灯全亮时的矩阵
*/
private static void solveAllLight(LightsOff lo)
{
lo.SetSize(5, 5);
lo.inputAllLight();
lo.solve();
for(int i=0; i<4; i++)
{
if(i==0)
{
lo.m_all[i] = lo.m_recorder;
}
else
{
lo.m_all[i] = lo.m_all[i-1].rotate();
}
}
int idx = 0;
CField[] m_all_temp = new CField[6];
for(int i=0; i<3; i++)
{
for(int j=i+1; j<4; j++)
{
m_all_temp[idx] = lo.new CField(lo.m_all[i]);
m_all_temp[idx].opAdd(lo.m_all[j]);
idx++;
}
}
// for(int i=0; i<4; i++)
// {
// lo.m_all[i].Print("830 m_all:" + i*90);
// }
//
// for(int i=0; i<3; i++)
// {
// for(int j=i+1; j<4; j++)
// {
// if(lo.m_all[i].opEq( lo.m_all[j] ))
// {
// System.out.println("lo.m_all i:" + i + " =j:" + j);
// }
// }
// }
//
// for(int i=0; i<6; i++)
// {
// m_all_temp[i].Print("835 m_all_2:" + i);
// }
for(int i=0; i<6; i++)
{
boolean b = true;
for(int j=i-1; j>=0; j--)
{
if(m_all_temp[j].opEq( m_all_temp[i] ))
{
b = false;
//System.out.println("lo.m_all_2 i:" + i + " =j:" + j);
}
}
if(b)
{
lo.m_all_2[lo.iZh] = m_all_temp[i];
lo.iZh++;
}
}
// for(int i=0; i<lo.iZh; i++)
// {
// lo.m_all_2[i].Print("835 m_all_3:" + i);
// }
}
/**
* 输入的数据
*/
private void input02() {
// m_field.LightsOff(0, 0);
// m_field.LightsOff(1, 0);
// 11100
// 10100
// 11000
// 10001
// 11011
m_field.SetLight(0, 0, 1);
m_field.SetLight(1, 0, 1);
m_field.SetLight(2, 0, 1);
m_field.SetLight(0, 1, 1);
m_field.SetLight(2, 1, 1);
m_field.SetLight(0, 2, 1);
m_field.SetLight(1, 2, 1);
m_field.SetLight(0, 3, 1);
m_field.SetLight(4, 3, 1);
m_field.SetLight(0, 4, 1);
m_field.SetLight(1, 4, 1);
m_field.SetLight(3, 4, 1);
m_field.SetLight(4, 4, 1);
System.out.println("m_field");
m_field.Print();
}
/**
* 获得所有的解
*/
private static void getAllSolve()
{
LightsOff lo = new LightsOff();
solveAllLight(lo); //求解灯全亮时的特殊解,获得其两两组合
lo.SetSize(5, 5);
lo.input02();
lo.solve();
for(int i=0; i<lo.iZh; i++)
{
CField f = lo.new CField(lo.m_recorder);
f.opAdd(lo.m_all_2[i]);
f.Print("解" + (i+2));
}
}
/**
* @param args
*/
public static void main(String[] args) {
//testSolve(); //测试求解过程
//testInverse(); //打印求逆矩阵的过程
//testRotate(); //测试矩阵旋转
//solveAllLight(); //求解灯全亮时的特殊解,或得其两两组合
getAllSolve(); //测试求解过程
}
CField m_field;
CField m_mask;
CField m_recorder;
CMatrix m_trans;
CMatrix m_switch;
int m_iUnitWidth;
CField[] m_all = new CField[4]; //四个特殊解
//CField[] m_all_temp = new CField[6]; //四个特殊解的两两组合
CField[] m_all_2 = new CField[6]; //四个特殊解的两两组合,去掉重复值
int iZh = 0; //有多少个特殊解的两两组合
}