P1062 卡牌游戏 官方题解
Gioush OJ · P1062 卡牌游戏
【题意简述】
两名玩家轮流拿走一对正面数值相同或背面数值相同的牌,无法操作者失败,判断先手是否必胜。
【正解】
用位掩码 表示仍在牌堆中的牌。预处理所有合法牌对对应的二进制掩码。定义 表示当前状态是否为必胜态,则
没有合法牌对时为必败态。记忆化搜索所有可达状态即可。
【正确性】
若存在一步走到必败态,当前玩家选择该步即可获胜;若所有合法操作都走到必胜态,对手总能获胜,当前状态必败。递推与最优策略定义完全一致。
【复杂度】
设合法牌对数为 ,时间复杂度 ,空间复杂度 。
【参考代码】
/*Author:EhundateghDate:2026/8/17Name:poker.cppYou steal,I kill.*/#include <vector>#include <cstdio>#include <cstring>#define MAXN 21using namespace std;int c,T,n,a[MAXN],b[MAXN];signed char Dp[1<<20];vector <int> Pair; int Calc(int Now){ if(Dp[Now]!=-1) return Dp[Now]; for(int i=0;i<(int)Pair.size();i++){ if((Now&Pair[i])==Pair[i]&&!Calc(Now^Pair[i])) return Dp[Now]=1; } return Dp[Now]=0;} void Solve(){ scanf("%d",&n);Pair.clear(); for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ if(a[i]==a[j]||b[i]==b[j]) Pair.push_back((1<<(i-1))|(1<<(j-1))); } } memset(Dp,-1,sizeof(signed char)*(1<<n)); puts(Calc((1<<n)-1)?"Ehundategh":"tfbz");} int main(){ scanf("%d%d",&c,&T); while(T-->0) Solve(); return 0;}