七段码

题目描述
小蓝要用七段码数码管来表示一种特殊的文字。
image
上图给出了七段码数码管的一个图示,数码管中一共有 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;
}

运行结果
image

posted on 2021-04-13 14:36  Laurance  阅读(1565)  评论(1编辑  收藏  举报