花了近1个半小时写完这道模拟……
因为既可以把牌放在顶部,又可以把牌放在底部,所以可以将每个牌堆用一个双端队列维护,然后按照题意模拟。但是还要判断循环游戏的情况,而且每一局游戏是由8个双端队列构成的。
这种情况可以搞成字符串处理,也可以自己手写Hash处理。然而,map/set中是可以以vector为类型的,而vector是可以直接比较大小的。 因此在vector中存放双端队列,用map/set记录局面即可。
代码( 建议谨慎观看以防头晕 ):
#include <cstdio>
#include <deque>
#include <vector>
#include <map>
typedef std::vector<std::deque<int> > State;
//用vector表示牌堆,按照先手牌再桌面上的顺序存放
std::map<State, bool> t;//用map判重
std::deque<int> hand, pile[7];//hand表示手牌,pile表示7堆牌
bool record() {//记录局面,如果重复返回0
State tmp;
tmp.push_back(hand);
for (int i = 0; i < 7; i++)
tmp.push_back(pile[i]);
if (t[tmp])
return 0;
t[tmp] = 1;
return 1;
}
bool check(std::deque<int> &q) {//判断是否满足1,2,3条件,不满足返回0
if (q.size() < 3)
return 0;//这个判断一定要有!(我因为一开始没写这个判断结果调了好长时间)
int first = q.front(), last = q.back();
q.pop_front(), q.pop_back();
if (first + q.front() + last == 10 || first + q.front() + last == 20 || first + q.front() + last == 30) {//1
hand.push_back(first);
hand.push_back(q.front());
hand.push_back(last);
q.pop_front();
return 1;
}
if (first + q.back() + last == 10 || first + q.back() + last == 20 || first + q.back() + last == 30) {//2
hand.push_back(first);
hand.push_back(q.back());
hand.push_back(last);
q.pop_back();
return 1;
}
q.push_front(first);
first = q.back();
q.pop_back();
//注意还原,下同
if (first + q.back() + last == 10 || first + q.back() + last == 20 || first + q.back() + last == 30) {//3
hand.push_back(q.back());
hand.push_back(first);
hand.push_back(last);
q.pop_back();
return 1;
}
q.push_back(first), q.push_back(last);
return 0;
}
int change(int &pos) {//发牌
while (pile[pos].empty())
pos = (pos + 1) % 7;//找到第一个非空的牌堆
pile[pos].push_back(hand.front()), hand.pop_front();//放牌
if (!record())
return -1;//平局
if (pile[pos].size() > 2)
while (check(pile[pos]));//题目说了要多次查看
if (hand.empty())
return 0;//手牌为空就输了
return 1;//这个返回值是凑数的,看看就好
}
int main() {
int card;
while (scanf("%d", &card) != EOF) {
if (!card)
break;
hand.push_back(card);
for (int i = 2; i <= 52; i++) {
scanf("%d", &card);
hand.push_back(card);
}
for (int i = 0; i < 7; i++)//先发每个牌堆1张牌
pile[i].push_back(hand.front()), hand.pop_front();
record();//记录初始局面
int times = 0, pos = 0;
while (1) {
bool ok = 1;
for (int i = 0; i < 7; i++)
if (!pile[i].empty())
ok = 0;//这个才是真正判断赢的
if(ok) {
printf("Win : %d\n", times+7);
break;
}
int c = change(pos);
if (c == -1) {
printf("Draw: %d\n", times+7);//算上前面7次发牌但不算当前这局
break;
}
else if (!c) {
printf("Loss: %d\n", times + 8);//算上前面7次发牌和当前这局
break;
}
++times, pos = (pos + 1) % 7;
}
//清空
hand.clear();
for (int i = 0; i < 7; i++)
pile[i].clear();
t.clear();
}
return 0;
}