描述
魔女宁宁有很多套占卜用的塔罗牌(这里为了方便表示,使用1~78的整数表示不同的塔罗牌牌面)。某天,部分塔罗牌在魔法的作用下两两结合,形成了双面塔罗牌。宁宁数了数,这些双面塔罗牌一共有 N 张,每张牌的牌面信息如下:第 i 张双面塔罗牌的正面为 A_i,反面为 B_i(都是1~78的整数)。宁宁想要好好利用这些无法再拿来占卜的双面塔罗牌,于是她想到了一个可以用这些牌来玩的博弈游戏,游戏规则如下。
最初,这 N 张双面塔罗牌平铺在桌面上,有两名玩家轮流进行操作(所有牌面信息都是已知的):从桌面上选择一对牌,要求它们正面相同或者反面相同,然后从桌面上移除这两张牌。如果不存在这样的牌对,则当前玩家输掉游戏,另一名玩家获胜。
宁宁邀请你来玩这个博弈游戏。现在你作为先手,想知道在双方都采取最优策略的情况下,你是否能够赢下游戏。
出题者为刘之流同学
输入
第 1 行一个整数 N (1<=N<=18)。
接下来是 N 行描述牌面信息的数据,每行两个整数 A_i 和 B_i (1<=A_i,B_i<=78)。
输出
若在双方都采取最优策略的情况下,你能够赢下游戏,则输出"YES",否则输出"NO"。
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
unordered_map<int, bool> memo;
bool canWin(vector<pair<int, int>>& cards, int usedMask) {
int n = cards.size();
if (memo.find(usedMask) != memo.end()) {
return memo[usedMask];
}
for (int i = 0; i < n; ++i) {
if (usedMask & (1 << i)) continue;
for (int j = i + 1; j < n; ++j) {
if (usedMask & (1 << j)) continue;
if (cards[i].first == cards[j].first || cards[i].second == cards[j].second) {
int newMask = usedMask | (1 << i) | (1 << j);
if (!canWin(cards, newMask)) {
memo[usedMask] = true;
return true;
}
}
}
}
memo[usedMask] = false;
return false;
}
int main() {
int n;
cin >> n;
vector<pair<int, int>> cards(n);
for (int i = 0; i < n; ++i) {
cin >> cards[i].first >> cards[i].second;
}
int initialMask = 0;
if (canWin(cards, initialMask)) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
return 0;
}