【栈和队列】蓝桥杯试题 拉马车

题目描述

OJ地址 http://lx.lanqiao.cn/problem.page?gpid=T447

小的时候,你玩过纸牌游戏吗?
  有一种叫做“拉马车”的游戏,规则很简单,却很吸引小朋友。

其规则简述如下:
  假设参加游戏的小朋友是A和B,游戏开始的时候,他们得到的随机的纸牌序列如下:
  A方:[K, 8, X, K, A, 2, A, 9, 5, A]
  B方:[2, 7, K, 5, J, 5, Q, 6, K, 4]

其中的X表示“10”,我们忽略了纸牌的花色。

从A方开始,A、B双方轮流出牌。

当轮到某一方出牌时,他从自己的纸牌队列的头部拿走一张,放到桌上,并且压在最上面一张纸牌上(如果有的话)。

此例中,游戏过程:
  A出K,B出2,A出8,B出7,A出X,此时桌上的序列为:

K,2,8,7,X

当轮到B出牌时,他的牌K与桌上的纸牌序列中的K相同,则把包括K在内的以及两个K之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。
  此时,A、B双方的手里牌为:
  A方:[K, A, 2, A, 9, 5, A]
  B方:[5, J, 5, Q, 6, K, 4, K, X, 7, 8, 2, K]

赢牌的一方继续出牌。也就是B接着出5,A出K,B出J,A出A,B出5,又赢牌了。
  5,K,J,A,5
  此时双方手里牌:
  A方:[2, A, 9, 5, A]
  B方:[Q, 6, K, 4, K, X, 7, 8, 2, K, 5, A, J, K, 5]

注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。

当某一方出掉手里最后一张牌,但无法从桌面上赢取牌时,游戏立即结束。

对于本例的初始手牌情况下,最后A会输掉,而B最后的手里牌为:

9K2A62KAX58K57KJ5

本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出-1。

输入:

输入为2行,2个串,分别表示A、B双方初始手里的牌序列。

输出:

输出为1行,1个串,表示A先出牌,最后赢的一方手里的牌序。

样例输入1:

96J5A898QA
6278A7Q973

样例输出1:

2J9A7QA6Q6889977

样例输入2:

25663K6X7448
J88A5KJXX45A

样例输出2:

6KAJ458KXAX885XJ645

思路:

考查的是栈和队列的用法,其实过程很简单,也很好理解,只要把过程模拟出来就可以了。大致流程:


手里的牌 用队列
出去的牌 用栈
	
每次出牌 遍历一下栈  判断能不能拿走下面的牌  如果拿走了,那就继续出牌  拿不走  就对方出牌 

要注意的一点就是对局的结束条件,出完了最后一张牌以后,还要判断一下能不能在“打出去的牌中拿回来一些牌”,不能认为手里的牌空了就是对局结束了,忽略了这一点的话,6个测试点可以通过4个,有一个测试会用到这个判断。

代码1

#include <bits/stdc++.h>

using namespace std;

stack<char> s;
queue<char> a,b;

int main(){

	string sc1,sc2;
	cin >> sc1;
	cin >> sc2;
	for(int i = 0; i < sc1.size();i++){
		a.push(sc1[i]);
		b.push(sc2[i]);
	}
	// A开始出牌
	s.push(a.front());
	a.pop();

	
	queue<char> *tmp_cur = &b;  //现在该出牌的 
	queue<char> *tmp_just = &a;  // 刚才出过牌的 
	
	while(true){
		// 刚出过牌 先判断一下能不能拿  检查的是刚才出牌的人,即tmp_just这个,可以的话,tmp_just继续出牌 
		char just_card = s.top();
		s.pop();  // 先弹出去  下边好判断 

		
		bool f = false;  // 拿没拿走的标志
		 
		string str_card = "";   
		/* 用于暂时存放从栈中遍历时  拿出去的那些牌,如果能拿走下面的牌,就把这个string里的char逐个push到刚才出牌人的手中
			如果不能,那就把这些char放回栈中 
		*/
		str_card += just_card;
		
		if(s.empty()){  //没牌了 
			// 下面没牌直接放  不检查
			s.push(just_card);
		}else{
			// 开始检查是否出过这牌 ;
			while(!s.empty()){
				
				if( just_card != s.top() ){
					str_card += s.top();   // 后拿出来的牌 往后放   入栈倒着来  给出牌人的话 正着给 
					s.pop();
				}else{
					// 可以拿走
					f = true;
					str_card += s.top();
					s.pop();   //先拿出来 
					
					for(int i = 0; i < str_card.size(); i++){
						tmp_just->push(str_card[i]);  //给刚才的出牌人 
					}
				}
				
				if(f){
					break;
				} 
			}
			// 检查结束
			if(!f){  // 没拿走 得把牌放回栈里 
				// cout << "历史出牌:"  << str_card << "所以拿不走" << endl;  
				for(int i = str_card.size()-1; i>=0 ; i--){
					s.push(str_card[i]);
				}
			} 
		} 
		
		
		
		if(f){  //拿走了  再出一张 
			s.push(tmp_just->front()); 
			tmp_just->pop(); 
		}else if(a.empty() || b.empty()){
			break;   //对局结束   手中没牌了,上一次出完就没了,并且在上边判断的时候,他出的最后一张牌也不能“拿回下面的牌”。 
		}else{  // 对方出一张
			s.push(tmp_cur->front()); 
			tmp_cur->pop(); 

			// 交换出牌的两个人
			queue<char> *temp = tmp_just;
			tmp_just = tmp_cur;
			tmp_cur = temp;  
		}
		
		
		// 进行下一次出牌 
		
	}
	
	if(!a.empty()){  //A赢 
		//cout << "A 赢了" << endl; 
		while(!a.empty()){
			cout << a.front();
			a.pop();
		}
		
	}else{
		// cout << "B 赢了" << endl; 
		while(!b.empty()){
			cout << b.front();
			b.pop();
		}
	}
	
	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值