华为OD机考,整理扑克牌⭐题(还有⭐⭐题) 牛客这个破OJ,输入是以文件格式输入,导致我在本地IDE中写的提交到OJ总是报错,上来就搞心态。
题目描述 给定一组数字,表示扑克牌的牌面数字,忽略扑克牌的花色,请按如下规则对这一组扑克牌进行整理: 步骤1. 对扑克牌进行分组,形成组合牌,规则如下: 斜体样式当牌面数字相同张数大于等于4时,组合牌为“炸弹”; 3张相同牌面数字 + 2张相同牌面数字,且3张牌与2张牌不相同时,组合牌为“葫芦”; 3张相同牌面数字,组合牌为“三张”; 2张相同牌面数字,组合牌为“对子”; 剩余没有相同的牌,则为“单张”; 步骤2. 对上述组合牌进行由大到小排列,规则如下: 不同类型组合牌之间由大到小排列规则:“炸弹” > “葫芦” > “三张” > “对子” > “单张”; 相同类型组合牌之间,除“葫芦”外,按组合牌全部牌面数字加总由大到小排列; “葫芦”则先按3张相同牌面数字加总由大到小排列,3张相同牌面数字加总相同时,再按另外2张牌面数字加总由大到小排列; 由于“葫芦”>“三张”,因此如果能形成更大的组合牌,也可以将“三张”拆分为2张和1张,其中的2张可以和其它“三张”重新组合成“葫芦”,剩下的1张为“单张” 步骤3. 当存在多个可能组合方案时,按如下规则排序取最大的一个组合方案: 依次对组合方案中的组合牌进行大小比较,规则同上; 当组合方案A中的第n个组合牌大于组合方案B中的第n个组合牌时,组合方案A大于组合方案B; 输入描述 第一行为空格分隔的N个正整数,每个整数取值范围[1,13],N的取值范围[1,1000] 输出描述 经重新排列后的扑克牌数字列表,每个数字以空格分隔 测试用例1 输入:1 3 3 3 2 1 5 输出 :3 3 3 1 1 5 2 测试用例2 输入:4 4 2 1 2 1 3 3 3 4 输出:4 4 4 3 3 2 2 1 1 3
我的思路:我当时考试的时候的思路就是针对map的key,val分别两次排序,其中key(牌大小)的优先级小于val(牌张数),但是map这个数据结构我是真玩不明白。然后自定义结构体数组解决问题,答题的思路相仿基数排序。 另外我没在找到OJ可以测试我代码,仅跑了两个测试用例(还有一些文章下面失败的例子,统统pass).欢迎大家评论区讨论and补充.【Tip:我相信自己思路没问题】
#include <iostream>
#include <unordered_map>
using namespace std;
typedef struct Card{
int key;
int val;
}card;
//针对自定义结构体魔改的冒泡排序,(考虑效率可以自行进行高效排序算法修改)
void sort(card arr[],int len){
for(int i = 0;i < len-1;i++){
for(int j = 0;j< len-i-1;j++){
if(arr[j].val < arr[j+1].val){
card tmp;
tmp.val = arr[j].val;tmp.key = arr[j].key;
arr[j].val = arr[j+1].val;arr[j].key = arr[j+1].key;
arr[j+1].val = tmp.val;arr[j+1].key=tmp.key;
}else if(arr[j].val == arr[j+1].val){
if(arr[j].key < arr[j+1].key){
card tmp;
tmp.val = arr[j].val;tmp.key = arr[j].key;
arr[j].val = arr[j+1].val;arr[j].key = arr[j+1].key;
arr[j+1].val = tmp.val;arr[j+1].key=tmp.key;
}
}
}
}
}
/*观测题目,可以知道本题目的难点在于葫芦牌的处理,
find函数就是针对处理葫芦牌的处理写的,
寻找三带二的,二中最大的两张牌
并返回其牌目*/
int find(card arr[],int len,int idx){
int comVal = -1;int max_i = -1;
int i = idx+1;
for(;i<len;i++ ){
if(arr[i].val>=2 && comVal<arr[i].key){
max_i = i;
comVal = arr[i].key;
}
}
arr[max_i].val -= 2;
sort(arr,len);
return comVal;
}
//此函数是用于打印最终结果的,第一参数是输出次数,第二参数是输出的牌目
void print(int i,int c){
for(;i>0;i--){
cout << c <<" ";
}
}
void map2arr(card arr[],unordered_map<int,int> map){
int index = 0;
//这里就比较简单了,把map的内容copy到自己定义的数组中去
for (auto it = map.begin(); it != map.end(); ++it) {
arr[index].key = it->first;
arr[index].val = it->second;
index++;
}
}
void done(card arr[],int len){
sort(arr,len);
//这里只需要对数组的第一个元素做相关操作,因为每次调用sort函数后,数组总是降序的
while(arr[0].val!=0){
if(arr[0].val==3){
print(arr[0].val,arr[0].key);
arr[0].val-=3;
int key_ = find(arr,len,0);
if(key_!=-1){
print(2,key_);
}
}else{
print(arr[0].val,arr[0].key);
//这里不要奇怪,就是针对已经输出的元素更新他的val值【val值代表的是他还可以被输出多少次】
arr[0].val-=arr[0].val;
sort(arr,len);
}
}
}
int main(){
/*我对map了解的比较少,唯一用得比较多的就是存储键值对,且键值唯一*/
int a;
/*我这里默认map的初始键值对元素都是0*/
unordered_map<int,int> map;
while(cin >> a){
//利用map的key唯一的特性统计牌数
map[a]=map[a]+1;
}
int mapSize = map.size();
//数组比价简单,所以我用数组来解决这道题目,但是素组类型是自定义的card类型。【其实大体思路有点类似于基数排序的思想】
card arr[mapSize];
map2arr(arr,map);
int len = sizeof(arr)/sizeof(arr[0]);
done(arr,len);
}