日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

麻将牌和牌问题

發布時間:2024/3/7 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 麻将牌和牌问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在知乎上看到一個問題,如何用程序判斷麻將牌是否和牌。和牌的規則為:14張麻將牌當中,必須要有一個對子,即兩張相同的牌,除去對子后,剩下的牌可以組合成”A, A, A”或者”A, A+1, A+2”兩種模式的組合,其中A為某種花色的某張牌。

我的解法是:
首先定義一下麻將牌在程序中的表示方式:
把萬,餅,條分別用連續的數字代表,比如:一萬到九萬用1到9表示,一餅到九餅用11到19表示,一條到九條用21到29表示。重要的是每一種牌內部數字是連續的,不同牌之間的數字不連續。對于風和中發白,每一種都用互相之間不連續的數字表示,比如中是31,發是33,白是35等等。
由于和牌中必需要有一個對子,所以我們的思路是,去除可能的對子,然后判斷剩下的牌是否可以表示成“A A A”或者“A A+1 A+2 ”這兩種模式的組合。
具體流程是:對輸入的14張麻將牌序列進行排序,排序后,由低到高依次尋找對子,如果隊列中沒有對子,那么肯定不是和牌,程序結束。找到對子后,將這兩張對子從序列中刪除,判斷其余的牌是否滿足下面的條件,如果滿足,則為和牌,結束,如果不滿足,則在排序后的輸入隊列中尋找下一個對子,重復本過程,直到條件1滿足或者搜索到序列結尾。

條件1:序列中的元素可以分為每3個元素一組,每組元素均為“A A A”或者“A A+1 A+2 ”的形式。

為了判斷一個序列是否滿足條件1,我們觀察到以下幾個性質:

性質1:排序后的麻將牌序列可以分割成若干子序列,其中每個子序列內部的元素是連續的,且不同序列間的元素不連續(連續指相鄰元素的值相同或值相差1)。

性質2:排序后的麻將牌序列滿足條件1的充分必要條件是,按性質1分割的每個子序列均滿足條件1。
性質3:如果一個序列滿足條件1,則按性質1分割后的子序列元素個數必定為3的整數倍。

于是,我們下一步要做的事情就是,將排序后的序列按照連續性分組,然后遞歸判斷每組是否滿足條件1,如果所有組都滿足條件1,則分組前序列也滿足條件1,否則不滿足。

為了判斷一個連續序列是否滿足條件1,可以分幾種情況考慮:
1. 如果序列中有3個元素,則直接判斷是否屬于條件1中的兩種情況即可;
否則,設A為序列中的最小值,
2. 如果A的個數大于等于3(即3或4),則序列滿足條件1的充分必要條件是序列去掉3個A后的剩余元素滿足條件1;
3. 如果A的個數小于3(即1或2),則序列滿足條件1的充分必要條件是序列去掉(A, A+1, A+2)后的剩余元素滿足條件1;

時間復雜度:
由于牌的個數是常數14,且每輪迭代數據規模都會減小,因此,該算法時間復雜度為O(1)。

代碼:

#include <iostream> #include <vector> #include <algorithm>using namespace std;static vector<int> result;//for debug void prtvct(const vector<int> &v, bool nxtline = true) {for (auto it = v.begin(); it != v.end(); ++it) {cout << *it << " ";}if (nxtline)cout << endl; }bool erase_by_val(vector<int> &in, int val) {for (auto it = in.begin(); it != in.end(); ++it) {if (*it == val) {in.erase(it);return true;}}return false; }void push_result(int a, int b, int c) {result.push_back(a);result.push_back(b);result.push_back(c); }bool shrink(vector<int> &in) {if (in[0] == in[1] && in[1] == in[2]) {push_result(in[0], in[1], in[2]);auto it = in.erase(in.begin());it = in.erase(it);in.erase(it);return true;} else {if (in[in.size()-1] - in[0] < 2) {return false;}}int i, t;for (i = 0, t = in[0]; i < 3; ++i, ++t) {erase_by_val(in, t);}push_result(t-3, t-2, t-1);return true; }void group(vector<int> &input, vector<vector<int> > &grp) {vector<int> member;if (input.begin() != input.end()) {member.push_back(input[0]);} else {return;}for (auto it = input.begin()+1; it != input.end(); ++it) {if (*it == *(it-1) || *it == *(it-1)+1) {member.push_back(*it);continue;}grp.push_back(member);member.clear();member.push_back(*it);}grp.push_back(member); }bool isLegal(vector<int> &input) {vector<vector<int> > grp;if (input.size() % 3 != 0) {return false;}if (input.size() == 3) {if (input[0] == input[1] && input[1] == input[2]) {push_result(input[0], input[1], input[2]);return true;}if (input[1] == input[0] + 1 && input[2] == input[1] + 1) {push_result(input[0], input[1], input[2]);return true;}return false;}group(input, grp);// for each groupfor (auto it = grp.begin(); it != grp.end(); ++it) {if (shrink(*it) == false) {return false;}if (isLegal(*it) == false) {return false;}}return true; }bool isHu(vector<int> &input) {sort(input.begin(), input.end());int i = 0;while (i < input.size()-1) {result.clear();auto incopy = input;if (input[i] == input[i+1]) {result.push_back(input[i]);result.push_back(input[i+1]);auto it = incopy.erase(incopy.begin() + i);incopy.erase(it);// processif (isLegal(incopy) == true) {return true;}}do { ++i; } while (i < input.size()-1 && input[i] == input[i-1]);}return false; }int main() {int n = 0;vector<int> input;cin >> n;for (int i = 0; i < n; ++i) {int a;input.clear();for (int j = 0; j < 14; ++j) {cin >> a;input.push_back(a);}if (isHu(input)) {cout << "Hu: ";prtvct(result);} else {cout << "Not Hu" << endl;}}return 0; }

總結

以上是生活随笔為你收集整理的麻将牌和牌问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。