【問題描述】
小藍要用七段碼數碼管來表示一種特殊的文字。
上圖給出了七段碼數碼管的一個圖示,數碼管中一共有 7 段可以發光的二 極管,分別標記為 a, b, c, d, e, f, g。
小藍要選擇一部分二極管(至少要有一個)發光來表達字符。在設計字符 的表達時,要求所有發光的二極管是連成一片的。
例如: b 發光,其他二極管不發光可以用來表達一種字符。
例如: c 發光,其他二極管不發光可以用來表達一種字符。這種 方案與上 一行的方案可以用來表示不同的字符,盡管看上去比較相似。
例如: a, b, c, d, e 發光, f, g 不發光可以用來表達一種字符。
例如: b, f 發光,其他二極管不發光則不能用來表達一種字符,因為發光 的二極管沒有連成一片。
請問,小藍可以用七段碼數碼管表達多少種不同的字符?
答案:
80
1:
暴力數
dfs實現指數型枚舉,然后自行根據是否連通一個一個數
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int n; int vis[20]; void dfs(int x) { if(x>n) { for(int i=1;i<=n;i++) if(vis[i]) cout<<i<<" "; cout<<endl; return ; } vis[x]=1; dfs(x+1); vis[x]=0; dfs(x+1); } int main() { cin>>n; // cout<<endl; dfs(1); return 0; }
2:
如果上面那個寫不好,可能會出現重復情況。下面這個是自行map去重代碼:
#include<iostream> #include<cstring> #include<map> #include<algorithm> #include<cmath> using namespace std; const int maxn=1e2+10; int vis[11]; int all=7; int cnt,sum=0; string s="0000000000"; map<string,int>mp; int dfs(int x) { if(x==cnt+1) { string s2; for(int i=1;i<=all;i++) s2+=s[i]; mp[s2]++; if(mp[s2]==1) {sum++; for(int i=1;i<=all;i++) if(s[i]!='0') cout<<s[i]; cout<<endl; } return 0; // cout<<sum<<endl; } for(int i=1;i<=all;i++) { if(s[i]=='0') { s[i]=i+'0'; dfs(x+1); s[i]='0'; } } } int getlcm(int a,int b) { return a*b/__gcd(a,b); } int main() { cnt=1;//cnt==1,2,3,4,5,6,7。自行更換值。 dfs(1); // cout<<sum<<endl; }
3:
二進制枚舉+並查集判聯通
1:首先說明:
(1):1<<7的意思是,把1左移七位。換成二進制就是:10000000
那么<(10000000)(二進制)的,就是0位~6位的所有情況。、
(2):第78行:if( i&(1<<j) )
假如 i 的二進制和 1<<2的二進制分別為:
1010100
0000100
如果if結果為真,說明i的第2位為1,即題目里的:發光
所以可以根據這個if,來枚舉所有 i 二進制中為1的位置
2:並查集判聯通。
這個就沒得說了,根據圖,一個一個連上就行。
每次判斷vis[i]==1而且pr[i]==i的有幾個,1個,就說明本次 i 的二進制只有一個連通塊,符合要求,cnt++;
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=1e2+10; int pr[11],vis[11]; void init(){memset(vis,0,sizeof(vis)); for(int i=0;i<=8;i++) pr[i]=i; } int find(int x){ if(x!=pr[x])return pr[x]=find(pr[x]); return x; } void add(int a,int b) { int fa=find(a),fb=find(b); if(fa!=fb) pr[fa]=fb; return ; } void check(int x) { vis[x]=1; if(x==0) { if(vis[1])add(0,1); if(vis[5])add(0,5); if(vis[6])add(0,6); } if(x==1) { if(vis[0])add(1,0); if(vis[6])add(1,6); if(vis[2])add(1,2); } if(x==2) { if(vis[1])add(2,1); if(vis[3])add(2,3); if(vis[6])add(2,6); } if(x==3) { if(vis[2])add(3,2); if(vis[4])add(3,4); } if(x==4) { if(vis[5])add(4,5); if(vis[6])add(4,6); if(vis[3])add(4,3); } if(x==5) { if(vis[0])add(5,0); if(vis[4])add(5,4); if(vis[6])add(5,6); } if(x==6) { if(vis[1])add(6,1); if(vis[2])add(6,2); if(vis[4])add(6,4); if(vis[5])add(6,5); } return ; } int main() { int cnt=0; for(int i=1;i<(1<<7);i++) //枚舉所有排列 { init();//初始化 for(int j=0;j<=6;j++) { if(i&(1<<j))//1<<j的二進制表示,出現的第一個1與st中某個1同位置 { check(j);//加入連通 } } int ans=0; for(int j=0;j<=6;j++) { if(vis[j]&&pr[j]==j) ans++; } if(ans==1) cnt++; } cout<<cnt<<endl; return 0; }