[算法] 麻将序数牌组合方案
生活随笔
收集整理的這篇文章主要介紹了
[算法] 麻将序数牌组合方案
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
// 環境: 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;
}
以上代碼是模擬麻將的序數牌,如萬、筒、條,將同是萬字的牌按對子、刻、順子去組合, 列出所有可能的組合!
總結
以上是生活随笔為你收集整理的[算法] 麻将序数牌组合方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统防御工程v0.2
- 下一篇: windows 微信多开脚本