题目

CF442A Borya and Hanabi
在这里插入图片描述

算法标签: 枚举, 位运算优化, 模拟

思路

注意到, 颜色数量和数字数量都是 5 5 5, 因此可以使用位运算枚举需要选择的颜色数量数字数量, 如果能将所有牌覆盖到, 那么当前方案就是一个合法的方案可以更新 a n s ans ans, 但是因为牌是可能有重复的, 需要开一个 s e t set set对牌进行去重, 需要将二维信息映射到一维, 也就是 a × 10 + b a \times 10 + b a×10+b每一种牌生成唯一的哈希值, 然后枚举所有的颜色和数字的选择情况

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <set>

using namespace std;

const int M = 1 << 5, INF = 0x3f3f3f3f;

int get(int x) {
   
	int ans = 0;
	for (int i = 0; i < 5; ++i) {
   
		ans += x >> i & 1;
	}
	return ans;
}


int main() {
   
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int n;
	cin >> n;

	map<char, int> mp;
	mp['R'] = 0;
	mp['G'] = 1;
	mp['B'] = 2;
	mp['Y'] = 3;
	mp['W'] = 4;

	set<int> st;
	for (int i = 0; i < n; ++i) {
   
		string s;
		cin >> s;
		int col = mp[s[0]];
		int val = s[1] - '1';
		st.insert(col * 10 + val);
	}

	n = st.size();

	int ans = INF;
	// 枚举所有颜色选择情况
	for (int i = 0; i < M; ++i) {
   
		// 枚举所有数字选择情况
		for (int j = 0; j < M; ++j) {
   
			set<int> vis;

			// 枚举所有牌
			for (auto &x : st) {
   
				int curr = 0;
				int col = x / 10;
				int val = x % 10;

				if (i >> col & 1) {
   
					curr += (col + 1) * 10;
				}
				if (j >> val & 1) {
   
					curr += val + 1;
				}
				vis.insert(curr);
			}

			if (vis.size() == n) {
   
				int cnt = get(i) + get(j);
				ans = min(ans, cnt);
			}
		}
	}

	cout << ans << "\n";
	return 0;
}