// 环境: centos7.2, g++ v4.8.5#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <map>using namespace std;enum CombineType
{CombineType_Null = 0, // 单牌CombineType_Dui = 1,  // 对子CombineType_Ke = 2,       // 刻CombineType_Shun = 3   // 顺子
};struct Combine                // 一种组合
{CombineType        type;vector<int>      cards;Combine(){type = CombineType_Null;}
};map<int, vector<int>> classify(vector<int>& v)
{map<int, vector<int>> m;for(auto& it : v){if(m.find(it) == m.end()){m[it] = {};}m[it].push_back(it);}#if 1for(auto& it : m){printf("%d: ", it.first);for(auto& it2 : it.second)printf("%d ", it2);printf("\n");}
#endifreturn m;
}// 从m中找一种符合组合类型为type的组合, 这个组合里最小的卡id为min
Combine findCombine(map<int, vector<int>>& m, int min, CombineType type)
{printf("开始查找: min=%d, type=%d\n", min, type);Combine comb;if(type == CombineType_Dui || type == CombineType_Ke)    // 查找对子或刻{uint n = type == CombineType_Dui ? 2 : 3;if(m[min].size() >= n)                        // 能找到对子或刻{for(int i = 0; i < n; i++)             // 从m[min]中取n张卡到comb.cards中{comb.cards.push_back(min);m[min].pop_back();if(m[min].empty())m.erase(min);}comb.type = type;}}else if(type == CombineType_Shun && min <= 7) // 8往后不可能组成顺子了{if(m.find(min) != m.end() && m.find(min+1) != m.end() && m.find(min+2) != m.end())  // 找到以min开始的顺子{comb.cards = {min, min+1, min+2};comb.type = type;for(auto& it : comb.cards){m[it].pop_back();if(m[it].empty())m.erase(it);}}}return comb;
}void display(Combine comb)
{printf("comb.type = %d, cards = ", comb.type);for(auto& it : comb.cards)printf("%d ", it);printf("\n\n");
}void displayCombines(vector<Combine>& v)
{for(auto& it : v){for(auto& it2 : it.cards){printf(" %d", it2);}printf(",");}printf("\n\n");
}// vector<Combine>:          一种组合方案
// vector<vector<Combine>>: 多种组合方案
vector<vector<Combine>> getCombines(vector<int>& v)
{vector<vector<Combine>> ret;auto m = classify(v);auto firstCard = [&m]()                     // 查找m中键最小的那个数{for(auto& it : m){return it.first;}return 0;};auto useCombine = [&m](Combine& comb)     // 使用组合{for(auto& it : comb.cards)              // 从m中删除comb中的卡牌{m[it].pop_back();if(m[it].empty())m.erase(it);}};auto recyle = [&m](Combine& comb)            // 回收comb中的卡牌{for(auto& it : comb.cards){if(m.find(it) == m.end()){m[it] = {};}m[it].push_back(it);}};printf("\n开始查找新的组合方案-----------------\n");vector<Combine> stack;int min = firstCard();CombineType oldType = CombineType_Null;        // 下次从此类型之后开始找do{bool b = false;auto types = {CombineType_Dui, CombineType_Ke, CombineType_Shun};for(auto& it : types){if(it <= oldType)                  // 以前找过的组合类型, 不再继续寻找continue;auto comb = findCombine(m, min, it);if(comb.type == it)                 // 找到一个组合{stack.push_back(comb);b = true;break;}}if(b)                     {printf("找到一个组合: ");display(stack.back());if(m.empty())                       // 找到一种组合方案(牌分配完了){ret.push_back(stack);printf("【找到一种组合方案】:");displayCombines(stack);}else{auto tmp = min;min = firstCard();                // 确定下次要找的牌if(tmp != min)oldType = CombineType_Null;  // 下次查找的类型重置}}else if(!stack.empty())                   // 有可回收的组合(回归查找准备)      {auto comb = stack.back();         // 取(复制)栈顶元素oldType = comb.type;               // 记录上次此组合开始查找的类型min = comb.cards[0];              // 下次从此牌开始找printf("回收一个组合: ");display(comb);recyle(comb);                     // 回收栈顶元素中的卡牌stack.pop_back();                  // 弹出栈顶组合}else                                  // 没有可回收的组合(即方案寻找结束)break;}while(true);return ret;
}int main()
{//vector<int> v = {1, 1, 1, 2, 2, 2, 8, 8};vector<int> v = {1, 1, 2, 4, 5, 6};auto vvc = getCombines(v);printf("--------------------------------\n");printf("vvc.size=%d\n", vvc.size());for(auto& vc : vvc){for(auto& comb : vc){printf("%d: ", comb.type);for(auto& c : comb.cards)printf("%d ", c);printf("\n");}printf("\n");}return 0;
}

以上代码是模拟麻将的序数牌,如万、筒、条,将同是万字的牌按对子、刻、顺子去组合, 列出所有可能的组合!

[算法] 麻将序数牌组合方案相关推荐

  1. C语言麻将递归,C++数据结构与算法——麻将胡牌算法(二:完全胡牌算法)

    虽然单花色胡牌算法面试时写出来了,但是完整的胡牌算法却没有写,既然遇到了,秉着不抛弃不放弃的精神,当然不能原谅懒惰的自己了.下面这篇为一个完整的胡牌算法. 胡牌规则除了以下几点,其余与单花色胡牌规则一 ...

  2. Unity3D 通用麻将胡牌算法

    https://blog.csdn.net/qq_38064109/article/details/78933589 正常的麻将胡牌方式为满足N * ABC + M *DDD +EE 的形式,及存在一 ...

  3. 可带癞子的通用麻将胡牌算法

    本文原创文章,转载注明出处,博客地址 https://segmentfault.com/u/to... 第一时间看后续精彩文章.觉得好的话,顺手分享到朋友圈吧,感谢支持. 笔者前段时间做过一款地方麻将 ...

  4. 麻将胡牌判定的判定算法

    麻将胡牌判定的判定算法 问题背景 : 简化了麻将规则,给定[1s-9s],[1b-9b],[1t-9t]一共27种牌,每种牌都有4张.需要判断给定的牌是不是胡牌. 胡牌的定义为: 14张牌里面由一个对 ...

  5. 麻将胡牌算法-癞子牌特别多(一)

    麻将内最核心的算法,每一次出牌,摸牌都需要使用到.(仅个人想法,想要更快速度,建用把算出来的结果存储下来,通过查表法来使用) 1.计算前准备 /*癞子数量*/protected byte laiNum ...

  6. 带赖子的麻将胡牌算法Java_有人讨论下麻将胡牌,出牌算法吗,求思路

    前段时间学会了打麻将,觉得老祖宗的智慧真的博大精深,很好玩,食胡的时候真兴奋啊,于是空余时间就想自己写个麻将游戏出来,模仿欢乐麻将那种,数学差,想了两个礼拜才想出一个胡牌算法,前段时间学会了打麻将. ...

  7. 麻将胡牌算法 极速(速度接近理论极限)

    此麻将胡牌算法优点: 1.可处理多赖子牌(万能牌) 2.算法速度极快:1ms可大约计算1W+副手牌是否可胡(带赖子.0.08us左右),不带赖子的牌型更快.(最新版的算法速度感觉已很接近理论极限值) ...

  8. 麻将胡牌算法的一种设计及其分析

    马勇波  陈欣庆 (解放军理工大学工程兵工程学院研究生二队,南京 210007)       摘  要  文章通过一个二维数组定义麻将的数据结构,并在此基础上设计了一种判断麻将是否胡牌的算法,该算法主 ...

  9. 麻将 胡牌 算法(任意癞子)

    分享一个麻将胡牌算法,支持多癞子,自己对麻将胡牌的理解写的一套快速识别胡牌逻辑,核心逻辑500行代码,仅对同条万进行处理,字花牌不包含在内,易理解,1M次随机胡牌牌型大概3秒左右.原创分享,我的算法也 ...

最新文章

  1. CVPR 2021|一个绝妙的想法:在类别不平衡的数据上施展半监督学习
  2. 【大数据-Hadoop】dbeaver
  3. matlab datetime时间处理、时间转换
  4. 代码签名证书,让软件真正拥有姓名!
  5. 我是这样开始学编程的
  6. Linux文件系统与日志
  7. 胰腺癌代谢生物标志物最新研究成果:诊断效率明显优于传统标志物
  8. Java企业面试算法新得体会之6大数据和空间限制问题6问
  9. python刷题_小李飞刀:用python刷题ing....
  10. android studio viewo,android studio 3.6.0 绑定视图新特性的方法
  11. linux C++获取当前文件所在路径的方法
  12. Redis-与spring的集成(XML形式)
  13. Python 被爆大 Bug,攻击者可远程代码执行漏洞!
  14. [51nod1106]质数检测
  15. 第24期、宠物医院管理系统
  16. PHP第三章到第七章
  17. 调研了700多家上市公司后,我们得聊聊“韧性”这件事
  18. JavaScript测试题
  19. 无线桥接后如何进入副路由器的页面?
  20. ESP32-C2 Homekit烧录示例

热门文章

  1. Win8 HTML5与JS编程学习笔记(二)
  2. 报告显示Q2 Android平板电脑全球市场份额达67%
  3. 在Solaris系统下如何更改网络配置?
  4. oracle failover 区别,Oracle DG failover 实战
  5. php pfm 改端口,罗马2ESF和PFM 修改建筑 军团 派系 兵种等等等很多东西的教程
  6. tb计算机存储单位_如何节省数TB的云存储
  7. leetcode51. N 皇后(回溯算法)
  8. linux创建sudo用户_Linux终极指南-创建Sudo用户
  9. 以下是ECMAScript 2016、2017和2018中所有新增功能的示例
  10. Python笔记 【无序】 【五】