七段码
题目描述
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二
极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。请问,小蓝可以用七段码数码管表达多少种不同的字符?
思路
直接二进制枚举或者深搜找所有情况,然后看找出的这种情况所选的边是不是连在一块儿,这个地方可以用并查集来维护,就像kruskal算法一样,先用结构体存所有的边,然后如果选这条边的话就将这个边的顶点拿出来,将一个点的祖宗节点更新为另一个点的祖宗节点,这样最后就可以找到哪些点是连在一起的。接着把这个图建出来即可,这是个7条边,6个顶点的图。
代码
#include <iostream>
using namespace std;
const int N = 20;
struct edge
{
int a, b;
}e[N];
int p[N];
int r[N]; // 选的每条边的端点
int cnt;
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
bool check(int x)
{
for (int i = 0; i < cnt - 1; i ++ )
if (find(r[i]) != find(r[i + 1])) return false;
return true;
}
int main()
{
for (int i = 0; i < 7; i ++ )
{
int a, b;
cin >> a >> b;
e[i] = {a, b};
}
int ans = 0;
for (int i = 1; i < (1 << 7); i ++ ) // 注意一条边都不选不算是合法情况,要排除
{
for (int j = 1; j <= 7; j ++ ) p[j] = j;
cnt = 0;
for (int j = 0; j < 7; j ++ )
if (i >> j & 1) // 这条边选上
{
int a = e[j].a, b = e[j].b;
r[cnt ++ ] = a, r[cnt ++ ] = b;
a = find(a), b = find(b);
p[a] = b;
}
if (check(i)) ans ++ ;
}
cout << ans << endl;
return 0;
}
运行结果