头像

Cyan

四川成都

深度强化学习炼丹师

2016年第七届蓝桥杯省赛-G. 剪邮票

2016年第七届蓝桥杯省赛-G. 剪邮票

2021-12-23 · 106次阅读 · 原创 · 数据结构与算法

原题链接

题面

如【图1.jpg】, 有12张连在一起的12生肖的邮票。

图1.jpg

现在你要从中剪下 5 张来,要求必须是连着的。(仅仅连接一个角不算相连)

比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

图2.jpg
图3.jpg

请你计算,一共有多少种不同的剪取方法。

题解

枚举,DFS,BFS

首先用 DFS 从 12 个数中选出 5 个数,将这五个数的位置用 g 数组标记起来, g[i][j] == true 代表该位置的数被选中。再用 BFS 判断这五个数是否连通即可。

答案:

116

代码

#include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; int ans, dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; bool g[3][4], v[3][4]; bool bfs() { memset(v, false, sizeof v); queue<PII> q; bool st = false; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { if (!st && g[i][j]) { //找到一个选出来的数,从它开始遍历 q.push({i, j}); v[i][j] = true; st = true; } } } int cnt = 1; while (q.size()) { PII now = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int ti = now.first + dir[i][0], tj = now.second + dir[i][1]; if (ti < 0 || ti >= 3 || tj < 0 || tj >= 4) continue; if (!g[ti][tj] || v[ti][tj]) continue; if (++cnt == 5) return true; q.push({ti, tj}); v[ti][tj] = true; } } return false; } void dfs(int k, int s) { if (s == 5) { //选出了 5 个数,进行连通性判断 if (bfs()) ans++; return; } if (k == 13) return; //该数所在坐标 int i = (k - 1) / 4; int j = (k - 1) % 4; //不选 dfs(k + 1, s); //选 g[i][j] = true; dfs(k + 1, s + 1); g[i][j] = false; //恢复现场 } int main() { dfs(1, 0); cout << ans << endl; return 0; }

标题: 2016年第七届蓝桥杯省赛-G. 剪邮票
链接: https://www.fightingok.cn/detail/185
更新: 2022-09-18 22:46:24
版权: 本文采用 CC BY-NC-SA 3.0 CN 协议进行许可