求解关灯游戏的全部解

关灯游戏,如果是灯全亮时,有个解。其解为
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; //有多少个特殊解的两两组合

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值