题意:
简单的扑克牌游戏,先定义扑克牌的大小如下:
- 3<4<5<6<7<8<9<10<11<12<13<1<2<11<12<13<1<2.
然后从第一个开始出最小的牌,然后其余玩家接着出牌,谁先没有手牌谁就获胜,并输出其余人的手牌点数和
出牌规则:
- 一开局从第一位玩家开始每人抽取5张牌,保证第一位玩家回合开始前每人手牌数不低于1张
- 玩家a出了一张2的话,从玩家a开始,所有人按顺序从牌堆抽取1张牌,然后玩家a出一张最小的牌
- 玩家出的牌必须得是上一张打出的牌的点数+1,否则可以选择出一张2,若是前面两种牌都没有,则跳过该玩家回合
- 如果所有的玩家的回合都被跳过(即上一张打出的牌为b,而所有的玩家都没有b+1的牌或者是2的牌)则从最后一个出牌的玩家开始,所有的玩家都需要从牌堆里面抽取1张牌,并出一张最小的牌
- 若是牌堆里面已经没有牌了,则忽略抽牌操作
思路:
其实难点在于题意,题意里面描述的是只要前面的玩家(我就理解成了上一个玩家,但实际上是上一个出牌的玩家)没有打出2,那么这个玩家就可以打出2...看了别人的AC代码才发现自己题意读错了.读懂了题意之后直接模拟即可
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e2 + 10, M = 2e4 + 10;
multiset<int>a[N];//3~13, 1
int b[M], cnt = 0, pre;
int n, m, T, ans[N];
int num[N];//2
void draw(int man)
{//抽牌
if(cnt >= m) return ;
if(b[cnt] == 15) num[man] ++;
else a[man].insert(b[cnt]);
cnt ++;
}
bool play(int man)
{//根据上一张牌的出牌
if(a[man].find(pre) != a[man].end())
a[man].erase(a[man].find(pre));
else
num[man] --, pre = 15;
return num[man] + a[man].size() > 0;
}
bool first(int man)
{//开局式出牌
if(a[man].size())
{
pre = *a[man].begin();
a[man].erase(a[man].begin());
}
else num[man] --, pre = 15;
return num[man] + a[man].size() > 0;
}
int main()
{
// freopen("1.txt", "r", stdin);
scanf("%d", &T);
for(int ca = 1; ca <= T; ca ++)
{
memset(num, 0, sizeof num);
cnt = 0;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i ++)
{
scanf("%d", b + i);
if(b[i] < 3) b[i] += 13;//1, 2 -> 14, 15
}
printf("Case #%d:\n", ca);
for(int i = 0; i < n; i ++)
for(int j = 0; j < 5; j ++)
draw(i);
int man = 0;
bool flag = first(0);
while(flag)
{
if(pre == 15)
{
for(int i = 0; i < n; i ++, man = (man + 1) % n)
draw(man);
flag = first(man);
}
else
{
pre ++;
man = (man + 1) % n;
int i;
for(i = 1; i < n; i ++, man = (man + 1) % n)
if(a[man].find(pre) != a[man].end() || num[man])
{
flag = play(man);
break;
}
if(i == n) pre = 15;//抽牌
}
}
for(int i = 0; i < n; i ++)
{
ans[i] = num[i] * 2;
while(!a[i].empty())
{
int t = *a[i].begin();
if(t == 14) t = 1;
ans[i] += t;
a[i].erase(a[i].begin());
}
if(ans[i]) printf("%d\n", ans[i]);
else puts("Winner");
}
}
return 0;
}