题意
题目连接:http://soj.sysu.edu.cn/1003
有纸牌游戏 Hit or Miss,游戏流程为:有一套叠好的纸牌(52 张,4 组,值为 1 - 13,花色在本游戏不重要)。
1. 玩家从 1 开始计数;
2. 如果当前计数与最顶端的纸牌数值相同,则扔掉最顶端纸牌,否则将最顶端的纸牌放入这叠纸牌最底部;
3. 计数加一,当计数超过 13 时,回到 1 重新计数。重复第二步;
该游戏也支持多名玩家,最开始只给第一名玩家一叠纸牌(52张)。
1. 玩家从上次自己计数停止处开始计数,最开始为 1;
2. 当玩家接受到纸牌时塞入自己维护的纸牌的最底部。
3. 如果当前计数与自己维护的纸牌最顶端的纸牌数值不同,将最顶端的纸牌放入这叠纸牌最底部,并回到第一步。否则,如果该玩家是最后一名玩家,则扔掉该纸牌,如果不是最后一名玩家,则将该纸牌传递给下一位玩家。数值相同的情况下,游戏都从下一位玩家开始;
4. 当所有牌都被扔了时,游戏胜利。
根据输入的玩家数量以及一套乱序纸牌,判断游戏是否能够胜利。如果能够游戏胜利,则给出结束时,每位玩家或传递或扔掉的最后一张纸牌的数值。否则输出 unwinnable。
题解
题目没有涉及复杂的算法,只要模拟这个游戏就好了……为每个玩家维护一个纸牌队列,然后循环就行。至于游戏是否能够胜利这点,我们只能以循环的次数决定了,当循环次数过大时,游戏结束。(我在提交时设置的次数为 5000,能够 AC)。
代码
代码这块也很朴实。不过我没有用到标准库提供的队列,自己粗暴地实现了一个循环队列来模拟每个玩家维护的纸牌队列~
#include <stdio.h>
#include <string.h>
#define CARD_MAX 52
#define CARD_CIRCULAR_MAX 53 // 循环队列的大小
#define MAX_TIMES 5000
// 循环队列,多用了一个空位
typedef struct deck {
char head;
char tail;
char cards[CARD_CIRCULAR_MAX];
} deck;
int main() {
int t, T, i, j, times;
int players, removed;
scanf("%d", &T);
for (t = 1; t <= T; ++t) {
removed = 0;
scanf("%d", &players);
deck cards[players];
for (i = 0; i < players; ++i) {
cards[i].head = 0;
cards[i].tail = 0;
memset(cards[i].cards, 0, sizeof(cards[i].cards));
}
// 第一位玩家的初始纸牌
for (i = 0; i < CARD_MAX; ++i)
scanf("%d", &(cards[0].cards[i]));
cards[0].head = 0;
cards[0].tail = i;
short last_count[players];
short last_discard[players];
memset(last_count, 0, sizeof(last_count));
memset(last_discard, 0, sizeof(last_discard));
times = 0;
// times 判断终止条件
while (times++ < MAX_TIMES && removed != CARD_MAX) {
for (i = 0; i < players && removed != CARD_MAX; ++i) {
// 玩家没有纸牌(循环队列空的)
if (cards[i].tail == cards[i].head) continue;
last_count[i] = last_count[i] == 13 ? 1 : last_count[i] + 1;
if (cards[i].cards[cards[i].head] == last_count[i]) {
// 更新用户丢弃或传递的纸牌
last_discard[i] = cards[i].cards[cards[i].head];
if (i == players - 1) {
removed++;
} else {
// 塞入下一个玩家纸牌底部
cards[i + 1].cards[cards[i + 1].tail] = cards[i].cards[cards[i].head];
cards[i + 1].tail = (cards[i + 1].tail + 1) % CARD_CIRCULAR_MAX;
}
// 当前玩家丢掉or传递纸牌
cards[i].head = (cards[i].head + 1) % CARD_CIRCULAR_MAX;
} else {
// 当前玩家把当前纸牌塞入自己纸牌底部
cards[i].cards[cards[i].tail] = cards[i].cards[cards[i].head];
cards[i].head = (cards[i].head + 1) % CARD_CIRCULAR_MAX;
cards[i].tail = (cards[i].tail + 1) % CARD_CIRCULAR_MAX;
}
}
}
printf("Case %d: ", t);
if (removed == CARD_MAX) {
printf("%d", last_discard[0]);
for (i = 1; i < players; ++i)
printf(" %d", last_discard[i]);
printf("\n");
} else
printf("unwinnable\n");
}
}
注
这次稍微用了下 struct!一开始我还用 ->
来取值,但其实是用 .
啦!结构体指针的话才用 ->
!
typedef struct a {
int q;
} a;
a t;
a* tp;
printf("%d, %d, %d", t.q, tp->q, (*tp).q);