征战蓝桥 —— 2016年第七届 —— C/C++A组第7题——剪邮票

剪邮票

在这里插入图片描述
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
在这里插入图片描述在这里插入图片描述
请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

Ideas

最终是想让我们计算”一共有多少种不同的剪取方法“,所以是要搜索所有的状态空间,应该用DFS。

这道题其实就是从12个格子中选出来5个,保证5个格子是联通的。

所以我们可以把问题建模:一个长度为12、元素为0的列表,从中选择5个格子置为1,然后判断5个1的位置对应到矩阵上是不是连通的。

我觉得这道题的考点就是连通块检查,连通块检查可以定义为一个单独的函数,经典的连通块计算方法还是通过DFS。

对于一个矩阵,首先要定义一个变量cnt,用于统计矩阵中为1的元素个数,然后整个遍历一遍矩阵,找到第一个为1的位置,先把 cnt + 1,然后进行 DFS,从当前位置开始,四个方向扩散,如果遇到值为1的元素,则置为0。

注意哈,此时如果所有的1是连通的,那么我从一个1出发,就可以将所有的1都置为0,后面继续遍历矩阵就不会再遇到值为1的元素,所以最后判断是不是连通块就是判断 cnt == 1。

OK,然后就可以开始写代码啦。

Code

C++

#include <algorithm>
#include <iostream>

using namespace std;

int ans;

bool check(int arr[12]);

void dfs(int g[3][4], int i, int j);

int main(int argc, const char *argv[]) {
    int per[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
    do {
        if (check(per))
            ans++;
    } while (next_permutation(per, per + 12));
    cout << ans << endl;
    return 0;
}

bool check(int arr[12]) {
    int g[3][4];
    memset(g, 0, sizeof(g));
//将相应位置标注为1
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            if (arr[i * 4 + j] == 1)g[i][j] = 1;
        }
    }
//    经典连通块计算
    int cnt = 0;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            if (g[i][j] == 1) {
                dfs(g, i, j);
                cnt++;
            }
        }
    }
    return cnt == 1;
}

void dfs(int g[3][4], int i, int j) {
    g[i][j] = 0;
    if (i + 1 <= 2 && g[i + 1][j] == 1) dfs(g, i + 1, j);
    if (i - 1 >= 0 && g[i - 1][j] == 1) dfs(g, i - 1, j);
    if (j + 1 <= 3 && g[i][j + 1] == 1) dfs(g, i, j + 1);
    if (j - 1 >= 0 && g[i][j - 1] == 1) dfs(g, i, j - 1);
}

Python

from copy import deepcopy
from itertools import permutations


def check(m):
	def dfs(x, y):
		m[x][y] = 0
		for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
			nx, ny = x + dx, y + dy
			if -1 < nx < len(m) and -1 < ny < len(m[0]) and m[nx][ny] == 1:
				dfs(nx, ny)

	cnt = 0
	for r in range(3):
		for c in range(4):
			if m[r][c] == 1:
				dfs(r, c)
				cnt += 1
	return cnt == 1


if __name__ == '__main__':
	ans = set()
	state = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
	matrix = [[0] * 4 for _ in range(3)]
	for ste in permutations(state):
		# 将一维状态向量映射为二维矩阵
		for i in range(3):
			for j in range(4):
				matrix[i][j] = ste[i * 4 + j]

		string = ''.join([''.join(map(str, row)) for row in matrix])
		if check(deepcopy(matrix)) and string not in ans:   # 连通块检查
			print(string)
			ans.add(string)
	print(len(ans))

Answer: 116

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大风车滴呀滴溜溜地转

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值