2018ACM/ICPC南京站网络赛C-GDY (补题)(暴力模拟)

题目链接

题意:十三种牌1、2、...、13,和扑克牌一样,不过JQK换成了11、12、13,大小是一样的,即3<4<5<...<13<1<2。已知n个人,m张牌,初始每个人从1到n按顺序各抽五张牌,可能出现牌堆已抓完但是最后一个人手中不足五张的情况,然后游戏开始。游戏过程中,每名玩家轮流出一张牌,第一个出牌的玩家必须出自己手中最小的一张牌,最开始是1先出牌,如果前一名玩家出了某张牌,那么后一名玩家只能出“恰好”比它大的一张牌,或者出一张2(如果前一名玩家出的不是2),如果后一名玩家无法做到则跳过,换更后一名玩家接牌...如果某名玩家出牌后没有其他玩家能出牌,则从该玩家开始每名玩家从牌堆中抓一张牌(如果牌堆已抓完则忽略抓牌这一操作),然后再由该名玩家第一个出牌。当某个玩家的牌出光了且牌堆已抓完的时候该玩家为胜者,其余玩家将手里的所有牌的数值加起来作为输掉的分数。数据保证初始抓牌后每个人手中的牌数不为0。

解法当然是直接暴力模拟,不过这种模拟题一般在细节上会容易踩坑。
我在这里根据自己的经验讲一些坑点和细节:首先,每个人抓五张牌后虽然保证每个人手中都有牌,但最后一个人可能抓了不到五张牌就抓牌结束了,需要判是否break。
然后,每当有人出牌后都需要他判断手中剩余牌的数量和牌堆是否已抓完,如果剩余数量为0且牌堆已抓完说明游戏结束。
连续没人出牌需要用一个变量记录,如果连续n-1人没有出牌,这一轮出牌结束,从出牌的那个人开始抓牌。
正如出牌过程中要判断玩家是否已经出完了牌,抓牌过程中也需要判断牌堆是否已经抓完。
为了方便,我直接把1和2映射为14、15了,因此最好计算分数的时候需要转化为1和2。
最后是注意循环出牌和抓牌时别写错了,其实0到n-1的循环好写很多QAQ,但是我习惯了写1到n,常常不小心写错。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define INF 0x3f3f3f3f
const int N = 20010;
int t,n,m,cnt;
int num[205][20],pri[205],minnum;
int a[N];
int main(){
	scanf("%d",&t);
	For(cas,1,t){
		scanf("%d %d",&n,&m);
		For(i,1,m) scanf("%d",&a[i]);
		cnt=1;
		memset(num,0,sizeof(num));
		memset(pri,0,sizeof(pri));
		For(i,1,n){
			For(j,1,5){
				if(cnt>m)break;
				num[i][(a[cnt]<3)?(a[cnt]+13):a[cnt]]++,cnt++;
				pri[i]++;
			}
		}
		minnum=pri[1];
		For(i,2,n) if(pri[i]<minnum) minnum=pri[i];
		int now=1,tmp,tt;
		while(minnum>0){
			for(int j=3;j<=15;j++){
				if(num[now][j]>0){
					tmp=j;num[now][j]--;pri[now]--;break;
				}
			}
			if(pri[now]==0&&cnt>m){
				break;
			}
			tt=0;
			for(int i=now%n+1;;i=i%n+1){
				if(tmp==15) break; 
				if(num[i][tmp+1]>0) num[i][tmp+1]--,tmp++,pri[i]--,now=i,tt=0;
				else if(tmp<15&&num[i][15]>0) num[i][15]--,pri[i]--,tmp=15,now=i,tt=0;
				else{
					tt++;
				}
				if(tt==n-1) break;
				if(pri[i]==0&&cnt>m) break;
			}
			if(cnt<=m){
				for(int i=now;;i=i%n+1){
					num[i][(a[cnt]<3)?(a[cnt]+13):a[cnt]]++,cnt++;pri[i]++;
					if(cnt>m) break;
					if(i==((now-2)%n+n)%n+1) break;
				}
			}
			minnum=pri[1];
			For(i,2,n) if(pri[i]<minnum) minnum=pri[i];
		}
		printf("Case #%d:\n",cas);
		int ans;
		For(i,1,n){
			if(pri[i]==0){
				printf("Winner\n");
			}
			else{
				ans=0;
				For(j,3,15){
					if(num[i][j]>0)
					ans+=(num[i][j]*(j<14?j:(j-13)));
				}
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38515845/article/details/82347008