zoukankan      html  css  js  c++  java
  • 10.4考试 红心大战 大模拟

    题目描述

    相信大家都有玩过“红心大战”这款游戏。

    现在有 (4) 个玩家来进行操作,我们会介绍本题中的游戏规则和玩家的出牌策略,你的任务是根据初始局面来计算最后的得分情况。

    游戏开始时, (4) 名玩家平分一副扑克牌除去双王后的 (52) 张牌,即每名玩家 (13) 张牌。

    点数从小到大为 (2,3,4,5,6,7,8,9,10,J,Q,K,A) , 输入中会用 (11,12,13,1) 来表示 (J,Q,K,A)

    我们另用 (1,2,3,4) 分别表示梅花、方片、黑桃、红桃四种花色。

    这样可以用一个二元组来表示一张扑克牌。比如 ((2,7)) 来表示方片 (7)

    由于本题中手牌的位置直接影响了玩家的出牌,因此玩家会将手牌排序,规则为先比较花色,再比较点数。

    ((1,3),(1,1),(3,10),(4,2),(4,6)) 就是排好序的手牌。

    (4) 名玩家坐成一圈,一轮出牌定义为从某名玩家开始按顺时针顺序每人各出一张牌。

    第一轮,从持有梅花 (2) 的玩家开始出牌,他需要打出梅花 (2)

    以后每轮,第一个出牌的玩家都会打出手中最左边的一张牌。

    对于某轮并非第一个出牌的玩家,他会考虑本轮中已经打出的、花色与第一个出牌的玩家打出牌相同的、点数最大的牌。若该玩家没有与之相同花色的牌,他会将手中最右边的一张牌打出,否则有两种情况:

    • 若其手中存在与之相同花色且点数更小的牌,他会选择相同花色、点数更小的牌中点数最大的打出。

    • 若其手中与之花色相同的牌的点数都更大,他会选择相同花色、点数最大的牌打出。

    一轮游戏完成后,打出了与第一个出牌的玩家打出牌花色相同且点数最大的玩家收走这一轮打出的 (4) 张牌,并由他作为下一轮第一个出牌的玩家开始下一轮。所有牌打完后,统计每名玩家收走的牌。

    其中每有一张红桃牌,该玩家获得 (1) 分。收走黑桃 (Q) 的玩家得到 (13) 分。

    需要注意的是,若一名玩家得到了全部的 (26) 分,则改为他不得分,其他 (3) 名玩家各得 (26) 分。

    可以发现,本题中的规则与实际规则会有出入。

    本题中 (4) 名玩家按顺时针的编号为 (1,2,3,4)

    为了方便选手得到部分分,本题中玩家的牌可能是不完整的,即总量不足 (13) 张,但仍保证每人手牌数量相同、没有相同的牌且梅花 (2) 在其中一人手中。

    输入格式

    第一行一个正整数 (T) 表示数据组数。

    对于每组数据,第一行一个正整数 (n) 表示每人的手牌数,

    接下来 (4n) 行依次描述编号为 (1,2,3,4) 的玩家的手牌,每人用 (n) 行每行一个二元组来表示。

    注意给出的手牌不一定有序。

    输出格式

    对于每组数据输出一行 (4) 个数一次表示编号为 (1,2,3,4) 的玩家的得分。

    样例

    样例输入

    1
    2
    1 2
    4 13
    1 10
    2 11
    1 7
    1 4
    3 1
    3 9
    

    样例输出

    0 1 0 0 
    

    一看题目比较长,要么是特别毒瘤的题或者是大模拟题。

    考试的时候,怒码 (190+) 行,结果 (debug) 用了两个多小时。

    一些要注意的点

    • 注意 (A) 这张牌是最大的。
    • 对于某轮并非第一个出牌的玩家,他会考虑本轮中已经打出的、花色与第一个出牌的玩家打出牌相同的、点数最大的牌,这个牌的点数是会变的
    • 剩下的就是注意分情况讨论的一些细节

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    using namespace std;
    #define P pair<int,int>
    int T,n,st,score[10],c[10];
    bool vis[10][20];//表示这张牌有没有被用过
    vector<pair<int,int> > shu[10];//存每个人收的牌数
    struct pai
    {
    	int col; int num;
    }a[10][20];
    inline int read()
    {
    	int s = 0,w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    bool comp(pai a,pai b)
    {
    	if(a.col == b.col) return a.num < b.num;
    	return a.col < b.col;
    }
    pair<int,int> find_two()//找有梅花二的那个人
    {
    	for(int i = 1; i <= 4; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(a[i][j].col == 1 && a[i][j].num == 2)
    			{
    				return make_pair(i,j);
    			}
    		}
    	}
    }
    int find(int now,int col,int num)//出牌
    {
    	int id = 0;
    	int flag = 0;
    	for(int i = 1; i <= n; i++)
    	{
    		if(a[now][i].col != col || vis[now][i]) continue;
    		if(a[now][i].num < num)	{flag = 1; break;}//特判一下情况
    	}
    	if(flag == 1)
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			if(a[now][i].col != col || vis[now][i]) continue;
    			if(a[now][i].num > num) break;
    			else if(a[now][i].num > a[now][id].num) id = i;
    		}
    	}
    	else
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			if(a[now][i].col != col || vis[now][i]) continue;
    			if(a[now][i].num > a[now][id].num) id = i; 
    		}
    	}
    	if(id == 0)
    	{	
    		id = n;
    		while(vis[now][id]) id--;
    	}
    	return id;
    }
    int slove(int n,int st)
    {
    	int id = 0;
    	if(n == 1)
    	{
    		P k = find_two();
    		int col = a[k.first][k.second].col;
    		int num = a[k.first][k.second].num;
    		c[k.first] = k.second;
    		for(int i = 1; i <= 3; i++)
    		{
    			int x = (k.first + i) % 4;
    			if(x == 0) x = 4;
    			c[x] = find(x,col,num);
    			if(a[x][c[x]].col == col) num = max(num,a[x][c[x]].num); 
    		}
    		for(int i = 1; i <= 4; i++)//找收牌的人
    		{
    			if(a[i][c[i]].col == col && a[i][c[i]].num >= a[id][c[id]].num) id = i;
    			vis[i][c[i]] = 1;
    		}
    		for(int i = 1; i <= 4; i++)//收牌
    		{
    			shu[id].push_back(make_pair(a[i][c[i]].col,a[i][c[i]].num));
    		}
    		return id;
    	}
    	else
    	{
    		int k = 1;
    		while(vis[st][k]) k++;
    		int col = a[st][k].col;
    		int num = a[st][k].num;
    		c[st] = k;
    		for(int i = 1; i <= 3; i++)
    		{
    			int x = (st + i) % 4;
    			if(x == 0) x = 4;
    			c[x] = find(x,col,num);
    			if(a[x][c[x]].col == col) num = max(num,a[x][c[x]].num);
    		}
    		for(int i = 1; i <= 4; i++)//找收牌的人
    		{
    			if(a[i][c[i]].col == col && a[i][c[i]].num >= a[id][c[id]].num) id = i;
    			vis[i][c[i]] = 1;
    		}
    		for(int i = 1; i <= 4; i++)
    		{
    			shu[id].push_back(make_pair(a[i][c[i]].col,a[i][c[i]].num));
    		}
    		return id;
    	}
    }
    int calc(int now)
    {
    	int res = 0;
    //	printf("-------->
    ");
    	for(int i = 0; i < shu[now].size(); i++)//计算每个人得分
    	{
    		P kk = shu[now][i];
    //		cout<<kk.first<<" "<<kk.second<<endl;
    		if(kk.first == 4) res++;
    		else if(kk.first == 3 && kk.second == 12) res += 13;
    	}
    	return res;
    }
    void work()
    {
    	n = read();
    	for(int i = 1; i <= 4; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			a[i][j].col = read();
    			a[i][j].num = read();
    			if(a[i][j].num == 1) a[i][j].num = 14;//A的点数是最大的
    		}
    	}
    	for(int i = 1; i <= 4; i++)
    	{
    		sort(a[i]+1,a[i]+n+1,comp);//先对牌拍一下序
    	}
    	int step = 0, st = 0;
    	while(step != n)//模拟每一轮的情况
    	{
    		step++;
    		st = slove(step,st);
    	}
    	for(int i = 1; i <= 4; i++)
    	{
    		score[i] = calc(i);
    		if(score[i] == 26)
    		{
    			for(int j = 1; j <= 4; j++)//得分情况2
    			{
    				printf("%d ",j != i ? 26 : 0);
    			}
    			printf("
    ");
    			return;
    		}
    	}
    	for(int i = 1; i <= 4; i++)
    	{
    		printf("%d ",score[i]);
    	}
    	printf("
    ");
    	return;
    }
    void clear()
    {
    	for(int i = 1; i <= 4; i++)//多测数据要清空
    	{
    		shu[i].clear();
    	}
    	memset(vis,0,sizeof(vis));
    	memset(score,0,sizeof(score));
    }
    int main()
    {
    //	freopen("hearts.in","r",stdin);
    //	freopen("hearts.out","w",stdout);
    	T = read();
    	while(T--)
    	{
    		clear();
    		work();
    	}
    //	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    前端常用插件收藏文章
    vue+ts修改父组件属性的写法。
    JS new date在IOS出现的问题
    js 和各种屏幕高度的写法
    react 配置ant时遇见的一个Error: Multiple configuration files found. Please remove one: – package.json#babel – .babelrc 解决方案
    vue 的sync用法
    VUE Right-hand side of ‘instanceof’ is not an object 解决方案
    记录一下navicat的快捷键
    什么是servlet(转)
    Java位运算在程序设计中的使用:位掩码(BitMask)
  • 原文地址:https://www.cnblogs.com/genshy/p/13770458.html
Copyright © 2011-2022 走看看