ACM/ICPC2018北京网络赛-Hihocoder1830 : Cheat(模拟)
ACM/ICPC2018北京网络赛-Hihocoder1830 : Cheat
描述
Cheat is a card game played by four players sitting around a table. They are numbered from 1 to 4 in clockwise order.
A pack of 52 cards is used. There are 13 ranks from low to high: A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, and four cards for each rank. At the beginning, each player gets 13 cards in hand randomly. The first player who discards all his cards is the winner.
The game consists of multiple rounds.
In each round: At first, a player, let's call him as a "round holder", put down some face-down cards on the table and makes a statement about the rank of those cards (such as "These are two Qs") . In a statement, all cards are of the same rank. Round holder can lie if he wants to. Then, other players will decide whether to challenge the statement in turn according to clockwise order. If nobody challenges, this round ends and the cards remains on the table. If somebody challenges, the cards put down by the round holder will be revealed. If the statement is true, the challenger takes back all cards on the table, and this round ends. If the statement is a lie, the round holder takes back all cards on the table, and this round also ends.
Player 1 is the first round holder. And players take turns to be the round holder according to clockwise order until someone wins. The first round holder must state that the cards he put down on the table are all rank A. Other statements must be exactly one rank higher than the previous statement (But rank K is followed by rank A). If a round holder has no cards of the required rank, he has to lie.
The first player who empty his hand at the end of a round is the winner.
Assume players played with the following strategies:
Player 1:
-
When being the round holder, he always makes a true statement and put down one card of the required rank if he can. If he can't, he always put down one card with the minimum lexicographic rank order. (10<2<3<…<9<A<J<K<Q)
-
Challenge the round holder if he is the next round holder and he has to lie in the next round.
-
Challenge the round holder if the round holder states that he put down p cards of rank X, and player 1 has q cards of rank X in his hand, and p+q>4.
Player 2:
-
When being the round holder, he always makes a true statement and put down all cards of the required rank if he can. If he can't, he always put down one card with the minimum lexicographic rank order. (10<2<3<…<9<A<J<K<Q)
-
Challenge the round holder if and only if he is the next round holder and he has to lie in the next round.
Player 3:
-
When being the round holder, he always makes a true statement and put down all cards of the required rank if he can. If he can't, he always put down all cards of a rank whose number of cards is the minimum in his hand. If there are multiple choices, choose the cards with the minimum lexicographic order. (10<2<3<…<9<A<J<K<Q)
-
Challenge the statement if and only if he has all 4 cards of the stated rank in his hand.
Player 4:
-
When being the round holder, always put down all cards of the required rank if he has three or four of them. Otherwise, always put down all cards of the required rank (if any) along with one more card (if any) with the minimum lexicographic order. (10<2<3<…<9<A<J<K<Q)
-
Challenge the round holder if and only if the round holder has already emptied his hand.
Given the cards each player has at the beginning, could you please figure out the cards in each player's hand when the game ends?
输入
There are no more than 100 test cases.
For each test case:
Four lines, indicating the cards in player 1, 2, 3 and 4 respectively.
Each line contains 13 strings separated by white space, indicating the rank of each card.
It is guaranteed that the given 52 cards form a pack.
输出
For each test case:
Output four lines, each line has multiple strings separated by white space, indicating the cards in each player's hand ordered by rank. The line for the winner is "WINNER". It is guaranteed that there are at most 1000 rounds each game.
样例输入
A 2 3 4 5 6 7 8 9 10 J Q K
A 2 3 4 5 6 7 8 9 10 J Q K
A 2 3 4 5 6 7 8 9 10 J Q K
A 2 3 4 5 6 7 8 9 10 J Q K
K A A A 5 5 5 5 9 9 9 9 K
A 2 2 2 2 6 6 6 6 10 10 10 10
3 3 3 3 7 7 7 7 J J J J K
4 4 4 4 8 8 8 8 Q Q Q Q K
样例输出
2 6 7 10 J
3 7 8 J Q
4 8 9 Q K
WINNER
A A 5 5 5 9 9 9 K
WINNER
K
A A 2 2 2 2 3 3 3 3 4 4 4 4 5 6 6 6 6 7 7 7 7 8 8 8 8 9 10 10 10 10 J J J J Q Q Q Q K K
题解
题意
有种英语等级考试阅读题的感觉,一上来一看就知道是个模拟。
大概是高中物理竞赛时候最爱玩的游戏。从扑克牌A-K开始进行循环,设为当前状态牌,每个人轮流坐庄,做庄时候按照一定策略放下扑克牌然后声明放下的牌为当前状态牌,如果没人质疑的话,进入下一个状态。直到达到K,然后从A重新开始循环。4个玩家给出放置牌和质疑的策略,给出开始的扑克牌状态,问结束时的状态。
放牌策略:
玩家1:如果能放置的话,放置一张。否则,放置一张字典序最小的
玩家2:如果能放置的话,全部放置。否则,放置一张字典序最小的
玩家3:如果能放置的话,全部放置。否则,放置全部牌数最小且相同时字典序较小的
玩家4:如果牌数是3或4张时,全部放置。否则,全部放置当前牌,且放置一张额外的字典序最小的
质疑策略:
玩家1:如果下一轮为玩家1且玩家1必须说谎,或者当前声明的牌数+玩家1手牌中的牌数>4,则质疑
玩家2:如果下一轮为玩家2且玩家2必须说谎则质疑
玩家3:如果玩家3持有4张当前牌,则质疑
玩家4:如果有一人手牌为空,则质疑
思路
模拟 没啥多说的,不过确实恶心。一些细节:
- 字典序,看了半天的错误。按照字典序K是在Q前面(即:K<Q)
- 玩家1的质疑策略有一条是指当前状态下的p+q>4 与之前的状态无关,需要每次保存当前状态的情况
- 玩家3的放牌策略,找到字典序最小且牌数最小的去放。注意剔除0张牌的情况。直接找会直接找到0张牌。
- 玩家4的放牌策略在不足3张时候并不一定是错误的放牌。例如:当前状态为7时,玩家4只有2张牌,而除此以外没有其他牌,则其实当前状态是正确的。只有有其他一张牌放入时候才为假。
- 注意只能质疑别人,不能质疑自己。回合完成后,牌是放置在桌子上的。只有质疑情况发生后,才会发生牌的清空。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
int T;
int hand[5][14];
char ins[10];
int lex[14]={0,10,2,3,4,5,6,7,8,9,1,11,13,12};
int now[60];
int face[13]={13,1,2,3,4,5,6,7,8,9,10,11,12};
int nc;
int tot = 1;
int numflag = 0;
vector<int>rcard;
struct Node{
int flag;
int ind;
}chaflag;
void init(){
memset(hand,0,sizeof(hand));
memset(now,0,sizeof(now));
rcard.clear();
tot = 1;
nc = 0;
numflag = 0;
}
int getnum(char s){
if(s=='A') return 1;
if(s=='J') return 11;
if(s=='Q') return 12;
if(s=='K') return 13;
if(s=='1') return 10;
else return s-'0';
}
int jud(){
for(int i=1;i<=4;i++){
int flag = 1;
for(int j=1;j<=13;j++){
if(hand[i][j]!=0) flag = 0;
}
if(flag==1) return 1;
}
return 0;
}
void put(int x,int cur){
if(x==1){
chaflag.ind = 1;
if(hand[x][cur]!=0){
now[nc++] = cur;
rcard.push_back(cur);
hand[x][cur]--;
chaflag.flag = 1;
}else{
for(int i=1;i<=13;i++){
int zidian = lex[i];
if(hand[x][zidian]!=0){
now[nc++] = zidian;
rcard.push_back(cur);
hand[x][zidian]--;
chaflag.flag = 0;
break;
}
}
}
}else if(x==2){
chaflag.ind = 2;
if(hand[x][cur]!=0){
while(hand[x][cur]>0){
now[nc++] = cur;
rcard.push_back(cur);
hand[x][cur]--;
}
chaflag.flag=1;
}else{
for(int i=1;i<=13;i++){
int zidian = lex[i];
if(hand[x][zidian]!=0){
now[nc++] = zidian;
rcard.push_back(zidian);
hand[x][zidian]--;
chaflag.flag = 0;
break;
}
}
}
}else if(x==3){
chaflag.ind = 3;
if(hand[x][cur]!=0){
while(hand[x][cur]>0){
now[nc++] = cur;
rcard.push_back(cur);
hand[x][cur]--;
}
chaflag.flag = 1;
}else{
int sav=0;
for(int i=1;i<=13;i++){
if(hand[x][lex[i]]!=0){
sav = lex[i];
break;
}
}
for(int i=1;i<=13;i++){
int ci = lex[i];
if(hand[x][sav]>hand[x][ci]&&hand[x][ci]!=0){
sav = ci;
}
}
while(hand[x][sav]>0){
now[nc++] = sav;
rcard.push_back(sav);
hand[x][sav]--;
}
chaflag.flag = 0;
}
}else{
chaflag.ind = 4;
if(hand[x][cur]>=3){
while(hand[x][cur]>0){
now[nc++] = cur;
rcard.push_back(cur);
hand[x][cur]--;
}
chaflag.flag = 1;
}else{
int cmpflag = 0;
while(hand[x][cur]>0){
now[nc++] = cur;
rcard.push_back(cur);
hand[x][cur]--;
}
for(int i=1;i<=13;i++){
int ci = lex[i];
if(hand[x][ci]>0){
now[nc++] = ci;
rcard.push_back(ci);
hand[x][ci] --;
chaflag.flag = 0;
cmpflag = 1;
break;
}
}
if(cmpflag==0) chaflag.flag = 1;
}
}
return ;
}
int challenge(int x,int cur){
int ind = tot%4;
if(ind==0) ind+=4;
if(x==1){
if(hand[x][face[(tot+1)%13]]==0&&ind==4){
return 1;
}
int numc = rcard.size();
if(numc+hand[x][cur]>4) return 1;
}else if(x==2){
if(hand[x][face[(tot+1)%13]]==0&&ind==1){
return 1;
}
}else if(x==3){
if(hand[x][cur]==4){
return 1;
}
}else{
int ci = chaflag.ind;
for(int i=1;i<=13;i++){
if(hand[ci][i]!=0) return 0;
}
return 1;
}
return 0;
}
char zhuan(int x){
if(x==1) return 'A';
if(x==11) return 'J';
if(x==12) return 'Q';
if(x==13) return 'K';
}
int main() {
while(~scanf("%s",ins)){
init();
hand[1][getnum(ins[0])]++;
for(int i=1;i<=4;i++){
int rin;
if(i==1) rin = 12;
else rin = 13;
for(int j=0;j<rin;j++){
scanf("%s",ins);
hand[i][getnum(ins[0])]++;
}
}
while(jud()==0){
rcard.clear();
int cur = face[tot%13];
int ind = tot%4;
if(ind==0) ind+=4;
int tf = 0;
put(ind,cur);
if(now[0]!=0) numflag =1;
for(int num = 1;num<4;num++){
int nowcha = ind + num;
if(nowcha>4) nowcha=nowcha-4;
if(challenge(nowcha,cur)==1){
tf = 1;
if(chaflag.flag==1){
for(int j=0;j<nc;j++){
hand[nowcha][now[j]]++;
}
}else{
for(int j=0;j<nc;j++){
hand[chaflag.ind][now[j]]++;
}
}
if(tf==1){
memset(now,0,sizeof(now));
nc = 0;
numflag = 0;
tf = 0;
}
break;
}
}
tot++;
}
for(int i=1;i<=4;i++){
int flag = 1;
for(int j=1;j<=13;j++){
int mmax = hand[i][j];
if(mmax!=0) flag =0;
for(int k=0;k<mmax;k++){
if(j>=2&&j<=10) printf("%d ",j);
else{
printf("%c ",zhuan(j));
}
}
}
if(flag ==1) printf("WINNER");
printf("\n");
}
}
}

浙公网安备 33010602011771号