七段碼

ltign發表於2024-03-04

一、問題描述

P8714 [藍橋杯 2020 省 B2] 試題 E:七段碼

二、問題簡析

我們可以把該數碼管看成一張圖:將二極體作為頂點,並編號(1~7);若二極體相鄰,則對應的頂點有無向邊連線。這樣,我們就得到了一張7個頂點的無向圖。題目要我們求,該圖的連通子圖的數量。
連通子圖:在無向圖 \(G\) 中,若任意兩個頂點之間都存在路徑使得它們相連通,則稱 \(G\) 為連通圖。
我們可以分兩步走:第一步,遍歷該圖的所有子圖;第二步,檢驗子圖的連通性。

2.1 遍歷子圖

在遍歷子圖時,可以利用掩碼來簡化運算。將二進位制的第 0 位與頂點 1 對應,第 1 位與頂點 2 對應 ······ 以此類推,7 個頂點一共要用 7 個二進位制位表示。若某個二進位制位是 0,表示子圖中沒有對應的頂點;若為 1,則有該頂點。
因此,我們可以遍歷二進位制位,來達到遍歷子圖的目的。因為二進位制可以轉換為十進位制,所以可以透過遞遍歷十進位制來達到遍歷二進位制的目的。
遍歷十進位制肯定不能無限制地遞增下去,要確定一個上限。若 7 個二進位制位都為 1,換算成十進位制就是 2^7 - 1,這就是上限。進行指數運算的複雜度較高,我們給該上限 +1,變成了 2^7,可以直接透過位操作 1 << 7 表示。

2.2 檢驗連通性

這裡採用 dfs 來檢驗連通性。


三、AC程式碼

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int quickin(void)
{
	int ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

bool vis[10], A[10], G[10][10];

int dfs(int x)
{
	if (!A[x] || vis[x])
		return 0;
	int ret = 1;
	vis[x] = true;
	for (int i = 1; i <= 6; i++)
	{
		if (G[x][i])
			ret += dfs(i);
	}
	return ret;
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
//	freopen("test.out", "w", stdout);
	#endif
	
	for (int i = 0; i < 10; i++)
	{
		int a, b;
		cin >> a >> b;
		G[a][b] = true;
		G[b][a] = true;
	}
	
	ll ans = 0;
	for (int i = 1; i < (1 << 7); i++)
	{
		fill(A, A + 10, false);
		fill(vis, vis + 10, false);
		int cnt = 0, st;
		for (int j = 1; j <= 7; j++)
			if ((i >> (j - 1)) & 1)
			{
				A[j] = true;
				st = j;
				cnt++;
			}	
		
		if (dfs(st) == cnt)
		{
			ans++;
//			for (int j = 1; j <= 6; j++)
//				if (A[j])    cout << j << ' ';
//			cout << endl;
		}
	}
	cout << ans << endl;
	
	return 0;
}

相關文章