puzzle(1012)战舰

目录

一,战舰

6*6

隐藏规则

8*8

39战舰(3)82(6)

120战舰(9)144(10)167(12)186(15)205(18)221(21)

二,扫雷战舰

12战舰(1)54(4)95(7)161(11)180(14)199(17)216(20)

三,边框战舰

24战舰(2)69(5)107(8)174(13)193(16)211(19)227(22)


一,战舰

在线play

找出藏在格子里的战船的位置,有些战船已经部分被揭示。
战船是一条连续不断的由黑方块组成的直线,各种大小的战船的数量显示在格子下方的提示里。
两条战船不能相邻(包括斜向),格子旁边的数字显示该行/列中被战船占据的格子数量。

6*6

 

隐藏规则

长为1的战舰由1个圆组成,长大于1的战舰除了两边的格子中间的都是正方形。

每个一共是三种不同的格子,初始局面给出的格子是哪一种是明确的。

8*8

 

39战舰(3)82(6)

智力游戏中的关卡,下同。

39战舰(3)

答案:

82(6)

首先

分析左边2列发现,只能是下面的情况(其实还有一种等价的情况,就是把第4行和第六行交换)

所以答案就很明显了

120战舰(9)144(10)167(12)186(15)205(18)221(21)

规则和39战舰(3)82(6)一样,但是从6*6变成了10*10,比较复杂了。

120战舰(9)

我干脆写了一个程序来计算答案。

代码:

#include<iostream>
using namespace std;

需要硬编码的3行///
const int m4 = 2, m3 = 2, m2 = 3, m1 = 3;	//战舰的个数,m4=2代表有2个长度为4的战舰
int line[nn] = { 2, 3, 2, 0, 5, 1, 0, 6, 2, 2 };	//列和
int row[nn] = { 1, 3, 1, 1, 4, 1, 5, 1, 2, 4 };	//行和
需要硬编码的3行///

const int nn = 10;		//游戏的维度
int avail[nn][nn];		//能否放战舰,一个是战舰不相邻的问题,一个是游戏开始的障碍物问题
int out[nn][nn];

void save(int avail[nn][nn], int line[nn], int row[nn], int save_avail[nn][nn], int save_line[nn], int save_row[nn])		//保存3个数组
{
	for (int i = 0; i < nn; i++)
	{
		for (int j = 0; j < nn; j++)save_avail[i][j] = avail[i][j];
		save_line[i] = line[i];
		save_row[i] = row[i];
	}
}

void re(int save_avail[nn][nn], int save_line[nn], int save_row[nn], int avail[nn][nn], int line[nn], int row[nn])		//还原3个数组
{
	for (int i = 0; i < nn; i++)
	{
		for (int j = 0; j < nn; j++)avail[i][j] = save_avail[i][j];
		line[i] = save_line[i];
		row[i] = save_row[i];
	}
}

bool g(int n);

bool f(int n, int l)		//n是递归深度,也是放了多少个战舰,l是战舰长度
{
	for (int pr = 0; pr < nn; pr++)		//横着放
	{
		for (int pl = 0; pl + l <= nn; pl++)		//(pr,pl)是战舰的最左那个格子
		{
			bool f = false;
			for (int k = pl; k < pl + l; k++)if (avail[pr][k] == 0)f = true;
			if (f)continue;

			int save_avail[nn][nn];	//回溯的时候保存avail
			int save_line[nn];
			int save_row[nn];
			save(avail, line, row, save_avail, save_line, save_row);

			row[pr] -= l;
			if (row[pr] < 0)
			{
				re(save_avail, save_line, save_row, avail, line, row);		//还原
				continue;
			}

			f = false;
			for (int k = pl; k < pl + l; k++)
			{
				line[k]--;
				if (line[k] < 0)f = true;
			}
			if (f)
			{
				re(save_avail, save_line, save_row, avail, line, row);
				continue;
			}

			for (int i = pr - 1; i <= pr + 1; i++)
			{
				if (i < 0 || i >= nn)continue;
				for (int j = pl - 1; j <= pl + l; j++)
				{
					if (j<0 || j >= nn)continue;
					avail[i][j] = 0;
				}
			}
			if (g(n + 1))
			{
				for (int k = pl; k < pl + l; k++)out[pr][k] = 1;
				return true;
			}
			else re(save_avail, save_line, save_row, avail, line, row);
		}
	}
	for (int pr = 0; pr + l <= nn; pr++)		//竖着放
	{
		for (int pl = 0; pl < nn; pl++)		//(pr,pl)是战舰的最上那个格子
		{
			bool f = false;
			for (int k = pr; k < pr + l; k++)if (avail[k][pl] == 0)f = true;
			if (f)continue;

			int save_avail[nn][nn];	//回溯的时候保存avail
			int save_line[nn];
			int save_row[nn];
			save(avail, line, row, save_avail, save_line, save_row);

			line[pl] -= l;
			if (line[pl] < 0)
			{
				re(save_avail, save_line, save_row, avail, line, row);
				continue;
			}

			f = false;
			for (int k = pr; k < pr + l; k++)
			{
				row[k]--;
				if (row[k] < 0)f = true;
			}
			if (f)
			{
				re(save_avail, save_line, save_row, avail, line, row);
				continue;
			}

			for (int i = pr - 1; i <= pr + l; i++)
			{
				if (i < 0 || i >= nn)continue;
				for (int j = pl - 1; j <= pl + 1; j++)
				{
					if (j<0 || j >= nn)continue;
					avail[i][j] = 0;
				}
			}
			if (g(n + 1))
			{
				for (int k = pr; k < pr + l; k++)out[k][pl] = 1;
				return true;
			}
			else re(save_avail, save_line, save_row, avail, line, row);
		}
	}
	return false;
}


bool g(int n)		//控制调用顺序
{
	if (n <= m4)return f(n, 4);
	else if (n <= m4 + m3)return f(n, 3);
	else if (n <= m4 + m3 + m2)return f(n, 2);
	else if (n <= m4 + m3 + m2 + m1)return f(n, 1);
	return true;
}

int main()
{
	for (int i = 0; i < nn; i++)
	{
		for (int j = 0; j < nn; j++)
		{
			avail[i][j] = 1;	//初始化,1表示可以放,0表示不可以
			out[i][j] = 0;
		}
	}

	g(1);
	for (int i = 0; i < nn; i++)
	{
		for (int j = 0; j < nn; j++)cout << out[i][j] << "  ";
		cout << endl;
	}
	cout << "end";
	system("pause>nul");
	return 0;
}

在最前面有3行是需要硬编码的,其他地方就固定不变了。

144(10)

规则和上面的差不多,唯一的区别是,有些格子开始的时候就不能放战舰,那么只需要在main函数里面对avail数组进行初始化的时候把这些格子对应的初始化为0就可以了。

167(12)

186(15)

205(18)

221(21)

这一关因为m3和m2比较大,所以运行的时候重复的情况比较严重,所以运行时间比较长。

二,扫雷战舰


 

12战舰(1)54(4)95(7)161(11)180(14)199(17)216(20)

12战舰(1)

这个游戏,规则确实和扫雷很像,而且也很简单

答案:

54(4)

答案:

95(7)

答案:

161(11)

有唯一解

首先可以确定:

接着可以确定:

最后可以得到唯一解:

180(14)

答案:

199(17)

答案:

216(20)

答案:

三,边框战舰

24战舰(2)69(5)107(8)174(13)193(16)211(19)227(22)

24战舰(2)

这个游戏的规则,有些类似于边框奇偶数独

没错,这一关是有唯一解的。

69(5)

规则和上面一样。

107(8)

174(13)

先搞定长为4和3的这3个战舰,有唯一的位置。

然后再放下面2个长为1的战舰,这2个战舰都可以往上移一格,不过结果是一样的,对其他的战舰没有任何影响。

上面的部分,很容易就找到一个解了,没有深究是不是唯一解。

193(16)

211(19)

一共有6种方案,不过都差不多

227(22)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值