✅
Sets ☁️
上一题链接: C/C++百题打卡[7/100]——【模板】并查集[洛谷].
百题打卡总目录: …
● 题目难度:⭐️⭐️⭐️⭐️⭐️
● 如果认真读了题。题目的意思也不难理解。
● 关键是我们要用什么样的 数据结构 来存储题目中所说的 “二极管之间的连接情况”?以及用什么 算法 来解决 “是否符合题目的发光要求”?
● 这里,我用的 矩阵 来存储题目中所说的 “二极管之间的连接情况”。用 并查集 来解决 “是否符合题目的发光要求”。
● 我们假设每一个 发光二极管 对应 一个数字,那 7 个二极管之间的连接情况如下:
int Links[7][7];
// 假设规定:a=0, b=1, c=2, d=3, e=4, f=5, g=6
Links[0][1] = Links[0][5] = 1; // ab, af
Links[1][0] = Links[1][2] = Links[1][6] = 1; // ba, bc, bg
Links[2][1] = Links[2][3] = Links[2][6] = 1; // cb, cd, cg
Links[3][2] = Links[3][4] = 1; // dc, de
Links[4][3] = Links[4][5] = Links[4][6] = 1; // ed, ef, eg
Links[5][0] = Links[5][4] = Links[5][6] = 1; // fa, fe, fg
Links[6][1] = Links[6][2] = Links[6][4] = Links[6][5] = 1; // gb, gc, ge, gf
● 每个二极管亮或不亮,我们用 Light[]
来表示,Light[0]=1
表示 a灯 亮,Light[3]=0
表示 d灯 不亮
● 如何输出 所有二极管的发光情况 呢?这里我也想了挺久的,网上几乎都是用的 dfs
,但是我想到另外一个巧妙的方法,如下:
for (int i = 1; i <= 127; i++)
{
int tmp = i;
int ind = 0;
while (ind < 7)
{
Light[ind] = tmp % 2;
tmp = tmp >> 1; // 或者 tmp = tmp / 2;
ind++;
}
for (int i = 0; i < 7; i++) // 初始化(用于并查集)
cout << Light[i] << " ";
cout << " ← 对应的数字是:" << i << endl;
}
◆ 输出结果为:【用 7
位二进制数来表示 所有二极管的发光情况,则总共有 127
种发光情况,但是其中有一些不符合 “发光要求”,我们后续要用 并查集 进行处理】
● 关于 并查集,可参考上一期的题目 C/C++百题打卡[7/100]——【模板】并查集[洛谷]。这里我就不赘述算法细节了,详见下面的注释。
#include
using namespace std;
int f[7];
int Links[7][7];
int ans;
int Light[7];
int Find(int x) // 并查集
{
if (x == f[x])
return x;
return f[x] = Find(f[x]);
}
int main()
{
// 假设规定:a=0, b=1, c=2, d=3, e=4, f=5, g=6
Links[0][1] = Links[0][5] = 1; // ab, af
Links[1][0] = Links[1][2] = Links[1][6] = 1; // ba, bc, bg
Links[2][1] = Links[2][3] = Links[2][6] = 1; // cb, cd, cg
Links[3][2] = Links[3][4] = 1; // dc, de
Links[4][3] = Links[4][5] = Links[4][6] = 1; // ed, ef, eg
Links[5][0] = Links[5][4] = Links[5][6] = 1; // fa, fe, fg
Links[6][1] = Links[6][2] = Links[6][4] = Links[6][5] = 1; // gb, gc, ge, gf
for (int i = 1; i <= 127; i++)
{
int tmp = i;
int ind = 0;
while (ind < 7)
{
Light[ind] = tmp % 2;
tmp = tmp >> 1; // 或者 tmp = tmp / 2;
ind++;
}
for (int i = 0; i < 7; i++) // 初始化(用于并查集)
f[i] = i;
for (int j = 0; j < 7; j++) // 遍历整个 Links[7][7]
{
if (Light[j] == 1) // 如果 j灯 亮, 再去看 Links[j][0]、Links[j][1]、...、Links[j][6]
{
for (int k = 0; k < 7; k++)
{
if (Links[j][k] == 1 && Light[k] == 1) // "j灯" 与 "k灯" 之间有连接, 且 "k灯" 如果也亮的话
{
int f_i = Find(j); // 找 "i灯" 的祖先节点(并查集)
int f_j = Find(k); // 找 "j灯" 的祖先节点(并查集)
if (f_i != f_j)
{
f[f_i] = f_j; // 合并为统一集合
}
}
}
}
}
int Father;
for (int i = 0; i < 7; i++)
{
if (Light[i] == 1)
{
Father = Find(i); // 随便找到一个集合的祖先结点
break;
}
}
int flag = 1;
for (int j = 0; j < 7; j++)
{
if (Light[j] == 1 && Father != Find(j)) // 如果某个 灯j 亮, 但它的祖先结点不是 Father
{
flag = 0; // 则说明这些 发光的二极管 没有连成一片
break;
}
}
if (flag == 1) // 所有发光的二极管的祖先结点都是一样的, 说明大家都连成了一片, 符合发光要求
ans++;
}
cout << ans << endl;
return 0;
}
// 答案是 80
● 感觉用 7位二进制
来表示 “所有二极管的发光情况” 这个想法很巧妙,但也不是我一时半会想出来的,可能需要多练多积累吧。
[1] 原题地址:https://www.lanqiao.cn/problems/595/learning/.
[2] 对于“并查集”讲得很不错的一篇知乎:《算法学习笔记(1) : 并查集》.
上一题链接: C/C++百题打卡[7/100]——【模板】并查集[洛谷].
百题打卡总目录: …
[C/C++百题打卡[8/100]——七段码[蓝桥杯2020省赛]
标签:并查集
不定期更新
2022/3/16