问题描述
如图,有 12 张连在一起的 12 生肖的邮票。
现在你要从中剪下 5 张来,要求必须是连着的(仅仅连接一个角不算相连)
比如下图中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
答案提交
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
答案:116
题解
DFS && 并查集:
解题思路
:
建图
:若某两个数字相邻,则在它们之间连一条边;- 先用
DFS
枚举出从12
个数字中选5
个数字的所有组合; - 由于
1 2 3
和1 3 2
都属于同一组合,所以为了避免重复计算,要从小到大枚举; - 最后用
并查集
判断是否只有一个连通块;
#include <iostream>
using namespace std;
const int N = 15;
int ans;
int p[N];
int e[N][N];
bool used[N];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int u, int start)
{
if(u == 5)
{
for (int i = 1; i <= 12; i ++) p[i] = i;
for (int i = 1; i <= 12; i ++)
for (int j = 1; j <= 12; j ++)
if(e[i][j] && used[i] && used[j])
p[find(i)] = find(j);
int cnt = 0;
for (int i = 1; i <= 12; i ++)
if(used[i] && p[i] == i)
cnt ++;
if(cnt == 1) ans ++;
return;
}
for (int i = start; i <= 12; i ++)
if(!used[i])
{
used[i] = true;
dfs(u + 1, i + 1);
used[i] = false;
}
}
int main()
{
e[1][2] = e[1][5] = 1;
e[2][1] = e[2][3] = e[2][6] = 1;
e[3][2] = e[3][4] = e[3][7] = 1;
e[4][3] = e[4][8] = 1;
e[5][1] = e[5][6] = e[5][9] = 1;
e[6][2] = e[6][5] = e[6][7] = e[6][10] = 1;
e[7][3] = e[7][6] = e[7][8] = e[7][11] = 1;
e[8][4] = e[8][7] = e[8][12] = 1;
e[9][5] = e[9][10] = 1;
e[10][6] = e[10][9] = e[10][11] = 1;
e[11][7] = e[11][10] = e[11][12] = 1;
e[12][8] = e[12][11] = 1;
dfs(0, 1);
cout << ans << endl;
return 0;
}