花了近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;
}