七段码
思路
并查集+递归
- 将abcdefg看成1234567数字,然后把能够联通的段用数组con[i][j]=1表示,比如1和2相邻可联通,则con【1】【2】=1
- 进行递归,先将1-7都点亮,有一种字符;再一步一步返回上一级,先是7灭,有一种字符;然后6灭,6灭的时候里面又分为7灭或者不灭,有几种字符;接着5灭,5灭的时候里面又分为6灭/不灭,7灭/不灭几种可能,有几种字符
- 定义一个全局变量ans,用来记录一共有几种字符,最后输出即可
代码(来源网络,后自己理解)
#include<stdio.h>
const int n=8; //方便起见,数组用到1-7,不用0,因此定义8
int vis[n],con[n][n],fa[n],ans=0;
/*vis[i]表示单个二极管i是否发光,con[i][j]用来表示i和j之间
是否联通,fa[i]表示i的根结点*/
int getfa(int i) //用并查集求根结点
{
if(fa[i]==i) return i;
else return fa[i]=getfa(fa[i]);
}
void dfs(int k)
{
int i,j,fx,fy,t;
if(k>7)
{
for(i=1;i<=7;i++)
fa[i]=i; //先把所有的i的根结点定为自己本身
for(i=1;i<=7;i++)
for(j=1;j<=7;j++)
if(con[i][j]==1 && vis[i]==1 && vis[j]==1)
//如果i和j是联通的,并且i是亮着的,j也是亮着的
{
fx=getfa(i);fy=getfa(j);//求i和j的根结点
if(fx!=fy)
fa[fy]=fx; /*将j的根结点和i的根结点相连,
比如1和2能联通并且都亮,1的根结点本来是1,2
的根节点本来是2,那之后fa[2]=1,也就是2的根
结点变成1,等到下次比较2和3的时候,就是
fa[3]=fx=getfa(2)=1,这样1 2 3 就能连在一起*/
}
t=0;
for(i=1;i<=7;i++)//求有几段亮的线路
if(fa[i]==i && vis[i]==1) t++;
if(t==1) ans++; /*比如1 2亮,4 5亮,那就说明有两段亮
的线路,不符合题目要求,必须只有一段
线路才可以算一种字符*/
return ; /*终止函数,跳回上一级,比如dfs(8)运行到这
里后,便不继续运行vis[8]=1这些,跳到上一级,即
dfs(7+1)运行结束,继续vis[7]=0;*/
}
vis[k]=1;
dfs(k+1);
vis[k]=0;
dfs(k+1);
}
int main()
{
con[1][1]=con[2][2]=1;con[1][6]=con[6][3]=1;
con[2][4]=con[3][5]=1;con[2][7]=con[7][6]=1;
con[3][7]=con[4][8]=1;con[3][7]=con[7][9]=1;
con[4][5]=con[5][10]=1;con[5][6]=con[6][5]=1;
con[5][7]=con[7][5]=1;con[6][7]=con[7][6]=1;
//将能联通相邻的两个二极管用1表示可联通
dfs(1);
printf("%d\n",ans);
}
答案
是通过看并查集和网上的代码理解的,有可能存在在某处的理解有误差