目录

puzzle1012战舰

puzzle(1012)战舰

目录


一,战舰

找出藏在格子里的战船的位置,有些战船已经部分被揭示。

战船是一条连续不断的由黑方块组成的直线,各种大小的战船的数量显示在格子下方的提示里。

两条战船不能相邻(包括斜向),格子旁边的数字显示该行/列中被战船占据的格子数量。

6*6

https://i-blog.csdnimg.cn/blog_migrate/07f1679241f664bfed99f4f4243763f6.png https://i-blog.csdnimg.cn/blog_migrate/c420e63559aacb2e626a25dc1a41692d.png

隐藏规则

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

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

8*8

https://i-blog.csdnimg.cn/blog_migrate/48fb909b54b5d5bf2761466581b92692.png https://i-blog.csdnimg.cn/blog_migrate/c354fb273557bbf0d5059d6f562614f4.png

39战舰(3)82(6)

中的关卡,下同。

39战舰(3)

https://i-blog.csdnimg.cn/blog_migrate/381ddb4fb129ae3fa4035d134e1598b0.jpeg

https://i-blog.csdnimg.cn/blog_migrate/014ddee870a44085e42e66d9fa41c424.jpeg

答案:

https://i-blog.csdnimg.cn/blog_migrate/d97b5cdcc7ab8279be8ba8c90a81ef0f.jpeg

82(6)

首先

https://i-blog.csdnimg.cn/blog_migrate/d787c20be7e5ef1bb8fff7b5bb6235c1.png

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

https://i-blog.csdnimg.cn/blog_migrate/0c92a9664ec500cc4064a170471af4da.png

所以答案就很明显了

https://i-blog.csdnimg.cn/blog_migrate/341672ebcc30349b7c06e674a02543a8.png

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

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

120战舰(9)

https://i-blog.csdnimg.cn/blog_migrate/85e822a3d126c5721f7db82b1685cbbe.jpeg

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

代码:

#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 行是需要硬编码的,其他地方就固定不变了。

https://i-blog.csdnimg.cn/blog_migrate/7bbbb7d0d0e47708463b81db47f90a25.jpeg

144(10)

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

https://i-blog.csdnimg.cn/blog_migrate/a0e6d9d115f98ae42075d8640c8b5225.png

167(12)

https://i-blog.csdnimg.cn/blog_migrate/ce341def32e8d8e1f85bba5682797643.png

186(15)

https://i-blog.csdnimg.cn/blog_migrate/ee5e2016f5233abd4c12da4a4fa0adb3.png

205(18)

https://i-blog.csdnimg.cn/blog_migrate/8db91fea6e5d943a18b730e5306a1ef7.png

221(21)

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

https://i-blog.csdnimg.cn/blog_migrate/f7292ba6b47d949bb6e00146cfb7fbae.png

二,扫雷战舰

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

12 战舰(1)

https://i-blog.csdnimg.cn/blog_migrate/e8380c74e01bedb1eeaed11f35d3e458.jpeg

https://i-blog.csdnimg.cn/blog_migrate/4dadaee732d6f3f51cd8182ccd91d378.jpeg

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

答案:

https://i-blog.csdnimg.cn/blog_migrate/0b9db8df0277726d349d1168509d7c11.png

54(4)

https://i-blog.csdnimg.cn/blog_migrate/e51bdeaddb0a81c1ff65570bb66b51ca.jpeg

答案:

https://i-blog.csdnimg.cn/blog_migrate/89bdbd7c87073ded54b99e4be40fd844.png

95(7)

答案:

https://i-blog.csdnimg.cn/blog_migrate/ae5644d1f4d2d55a710dc0a712352e77.png

161(11)

有唯一解

首先可以确定:

https://i-blog.csdnimg.cn/blog_migrate/1de83784e3ab2e5c2c61567bd17c9f7c.png

接着可以确定:

https://i-blog.csdnimg.cn/blog_migrate/f4620d0d0b2940223b8c275baf4bfb44.png

最后可以得到唯一解:

https://i-blog.csdnimg.cn/blog_migrate/c336128c5631124aaab6894442cf5b62.png

180(14)

答案:

https://i-blog.csdnimg.cn/blog_migrate/a9cfc70f240314df793ae8c39d3ffcc7.png

199(17)

答案:

https://i-blog.csdnimg.cn/blog_migrate/33c275c9c5d983a15e4bd4c4ad476b42.png

216(20)

答案:

https://i-blog.csdnimg.cn/blog_migrate/562be811bbc6dbacf9afa9d40afeb6f2.png

三,边框战舰

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

24 战舰(2)

https://i-blog.csdnimg.cn/blog_migrate/f9ff7faa3f57ddb4f71cb0266dfdfc0e.jpeg

https://i-blog.csdnimg.cn/blog_migrate/dce64bc3ad0c47f1bf9a94a0b6f4fa84.jpeg

这个游戏的规则,有些类似于

https://i-blog.csdnimg.cn/blog_migrate/82ba12455f9462981c165d9fb686894c.jpeg

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

69(5)

规则和上面一样。

https://i-blog.csdnimg.cn/blog_migrate/64bed763b4db6a091ac0b9e82e0b9617.png

107(8)

https://i-blog.csdnimg.cn/blog_migrate/5da03f561542a7ce02a61a842e0d6ed7.jpeg

174(13)

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

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

https://i-blog.csdnimg.cn/blog_migrate/e43a9bafee7d6eb14c21a56fbf0ae13a.png

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

https://i-blog.csdnimg.cn/blog_migrate/79e3ce0577a8f2ead9050b5083b43ea3.png

193(16)

https://i-blog.csdnimg.cn/blog_migrate/e28a09cc7094976a21d1bc950479e9ba.jpeg

211(19)

https://i-blog.csdnimg.cn/blog_migrate/a016b4d2592ff7bf6aa9fd5f26665d13.png

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

227(22)

https://i-blog.csdnimg.cn/blog_migrate/ffe5be87bcf67637a3aec007615b851d.png