撲克牌的順子

題目:從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2-10爲數字本身,A爲1,J爲11,Q爲12,K爲13,而大小王可以看成任意數字。  

我們需要把撲克牌的背景抽象成計算機語言。不難想象,我們可以把5張牌看成由5個數字組成的數組。大小王是特殊的數字,我們不妨把它們都當成0,這樣和其他撲克牌代表的數字就不重複了。

接下來我們來分析怎樣判斷5個數字是不是連續的。最直觀的是,我們把數組排序。但值得注意的是,由於0可以當成任意數字,我們可以用0去補滿數組中的空缺。也就是排序之後的數組不是連續的,即相鄰的兩個數字相隔若干個數字,但如果我們有足夠的0可以補滿這兩個數字的空缺,這個數組實際上還是連續的。舉個例子,數組排序之後爲{01345}。在13之間空缺了一個2,剛好我們有一個0,也就是我們可以它當成2去填補這個空缺。

於是我們需要做三件事情:把數組排序,統計數組中0的個數,統計排序之後的數組相鄰數字之間的空缺總數。如果空缺的總數小於或者等於0的個數,那麼這個數組就是連續的;反之則不連續。最後,我們還需要注意的是,如果數組中的非0數字重複出現,則該數組不是連續的。換成撲克牌的描述方式,就是如果一副牌裏含有對子,則不可能是順子。

其實在編程過程中,我們可以利用最大值和最小值的差來進行簡單的數學性質判斷即可。利用set的不重複性可以避免排序。

#include <iostream>
#include <set>
#include <vector>
using namespace std;

void GetMaxMin(const set<int>& setNum, int &nMax, int &nMin)//得到除0(大小王)外的最小值和最大值
{
	nMin=13;
	nMax=1;
	set<int>::const_iterator iter=setNum.begin();
	for(; iter!=setNum.end(); iter++)
	{
		if(*iter<nMin)
			nMin=*iter;
		if(*iter>nMax)
			nMax=*iter;
	}
}

int Del0Num(set<int>& setNum, const vector<int>& data)//將非零(大小王)元素加入set集合,set集合不能有重複元素的,如果有重複元素則舍掉,導致size變小
{
	int Num0=0;
	vector<int>::const_iterator iter=data.begin();
	for(; iter!=data.end(); iter++)
	{
		if(*iter!=0)
			setNum.insert(*iter);
		else
			Num0++;
	}
	return Num0;
}

bool IsContinuous(vector<int> data)
{
	int nMax=0, nMin=0;
	set<int> setNum;
	int num0=Del0Num(setNum, data);

	if(num0+setNum.size()<data.size())//set集合不能有重複元素的,如果有重複元素則舍掉,導致size變小
		return false;

	GetMaxMin(setNum, nMax, nMin);

	return nMax-nMin<=data.size()-1;//如果最大值和最小值的差小於向量size減1,則滿足連續性,0即大小王可以填補中間的空缺。
}

int main()
{
	vector<int> vec;
	for(int i=0; i<5; i++)
	{
		int temp;
		cin>>temp;
		vec.push_back(temp);
	}
	cout<<IsContinuous(vec)<<endl;

	return 0;
}


感謝:http://blog.csdn.net/unimen/article/details/6820975

發佈了90 篇原創文章 · 獲贊 22 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章