艰辛的晚上:蓝桥杯刷题:剪邮票
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
整体思路:找出选择5个格子的全排列,然后筛选出连通的即可
唉,自以为是,bfs的时候 n多加了1,看了好久。 接上正确 的代码吧:
#include<bits/stdc++.h>
using namespace std;
bool bfs(char m[][4])
{
int visited[3][4] = { 0 };
queue<pair<int, int> > que;
int n = 0; //n用来统计连通的1的个数,如果有5个,返回true;否则返回false;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
if (m[i][j] == '1')
{
visited[i][j] = 1;
que.push(make_pair(i, j)); //找到第一个出现的1 ,开始宽搜,判断是否连通
goto flag;
}
}
}
flag:
while (!que.empty())
{
int i = que.front().first;
int j = que.front().second; //一次判断上下左右是否为1,如果为1就入队
if (i - 1 >= 0 && m[i - 1][j] == '1'&&visited[i - 1][j] == 0)
{
visited[i - 1][j] = 1;
que.push(make_pair(i - 1, j));
}
if (i + 1 < 3 && m[i + 1][j] == '1'&&visited[i + 1][j] == 0)
{
visited[i + 1][j] = 1;
que.push(make_pair(i + 1, j));
}
if (j - 1 >= 0 && m[i][j - 1] == '1'&&visited[i][j - 1] == 0)
{
visited[i][j - 1] = 1;
que.push(make_pair(i, j - 1));
}
if (j + 1 < 4 && m[i][j + 1] == '1'&&visited[i][j + 1] == 0)
{
visited[i][j + 1] = 1;
que.push(make_pair(i, j + 1));
}
que.pop();
n++;
}
if (n == 5)
{
return true;
}
return false;
}
int main()
{
int sum = 0;
string s = "000000011111"; //必须这样初始化才可
do
{
int k = 0;
char ch[3][4]; //将字符串转化为数组,判断1所在的位置是否连通,若连通,就可以成功。
for (int i = 0; i<4; i++)
{
ch[0][i] = s[k++];
}
for (int i = 0; i<4; i++)
{
ch[1][i] = s[k++];
}
for (int i = 0; i<4; i++)
{
ch[2][i] = s[k++];
}
if (bfs(ch)) sum++; //宽搜判断是否连通
} while (next_permutation(s.begin(), s.end()));
cout << sum;
return 0;
}