UVa 131 The Psychic Poker Player

题目: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=107&page=show_problem&problem=67
对于每一个输入样例(10张牌),我们要构造出它所有的32种牌型组合,这是一个比较困难的地方,方法是用递归枚举。每次我们可以从手牌中分别选取0~5张牌,然后剩余的牌从牌堆中补充。从手牌中选牌,就是组合数C(5,0),C(5,1),C(5,2),C(5,3),C(5,4),C(5,5),这道题中,我们不仅要知道组合数是多少,更重要的是把具体的牌型构造出来。
我们可以把构造的牌临时存在temp数组中,然后构造它的每一位,即用5张手牌去填充该位,为了避免重复,假设当前我们用第cur1张手牌(下标从0开始)去填充,那么temp数组的下一位我们只能用第cur1张手牌后面的牌去填充,否则就重复了,因此我们要用一个变量cur1去限制使用手牌去填充的范围(即当前填充范围只能从cur1开始),并且不能超过总牌数-还需构造的牌数。这是一个递归的过程,具体实现请看代码中的structure函数。
当我们把具体的牌型构造出来后,即我们有了5张牌,然后我们就判断它的最好组合牌就可以了。
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cctype>
using namespace std;

struct card
{
	int point;
	char suit;
	bool operator == (const card &b)
	{
		if(point==b.point&&suit==b.suit)
			return 1;
		else return 0;
	}
};

int cur;//sum数组第一维的游标
card hand[5],deck[5],sum[32][5],temp[5];//sum把保存32种牌型

void input(string &tmp,int &point,char &suit)
{
	if(isalpha(tmp[0]))
	{
		switch(tmp[0])
		{
			case'A':point=1;break;
			case'T':point=10;break;
			case'J':point=11;break;
			case'Q':point=12;break;
			case'K':point=13;break;
		}
	}
	else
		point=tmp[0]-'0';
	suit=tmp[1];
}
void structure(int X,int cur1,int cur2,card *hand,card *temp)
{//还需选择X张牌,目前正在从hand数组的第cur1位开始构造temp数组的第cur2位
	if(X==0) 
	{
		for(int i=cur2;i<5;i++)//牌堆中选出牌补充
			temp[i]=deck[i-cur2];
		memcpy(sum[cur++],temp,sizeof(card)*5);
		return;
	}
	for(int i=cur1;i<=5-X;i++)
	{
		temp[cur2]=hand[i];
		structure(X-1,i+1,cur2+1,hand,temp);
	}
}
int cmp(void const *a,void const *b)
{
	return ((card *)a)->point-((card *)b)->point;
}
int solve(card *temp)//对于给定的5张牌,判断它的最好组合牌
{
	int i,flush=1,straight=0;
	qsort(temp,5,sizeof(card),cmp);
	if(temp[4].point-temp[3].point==1&&temp[3].point-temp[2].point==1&&temp[2].point-temp[1].point==1&&temp[1].point-temp[0].point==1||temp[0].point==1&&temp[1].point==10&&temp[2].point==11&&temp[3].point==12&&temp[4].point==13)
		straight=1;
	for(i=1;i<5;i++)
		if(temp[i].suit!=temp[0].suit)
		{
			flush=0;
			break;
		}
	if(flush&&straight) return 9;
	int cnt[14]={0},four=0,three=0,two=0;
	for(i=0;i<5;i++)
		cnt[temp[i].point]++;
	for(i=1;i<=13;i++) if(cnt[i]>1)
	{
		if(cnt[i]==2) two++;
		else if(cnt[i]==3) three++;
		else four++;	
	}
	if(four) return 8;
	if(three&&two) return 7;
	if(flush) return 6;
	if(straight) return 5;
	if(three) return 4;
	if(two==2) return 3;
	if(two) return 2;
	return 1;
}
int main()
{
	//freopen("in.txt","r",stdin);
	int i;
	string tmp;
	while(cin>>tmp)
	{
		cout<<"Hand: ";
		cout<<tmp<<' ';
		input(tmp,hand[0].point,hand[0].suit);
		for(i=1;i<5;i++)
		{
			cin>>tmp;
			cout<<tmp<<' ';
			input(tmp,hand[i].point,hand[i].suit);
		}
		cout<<"Deck: ";
		for(i=0;i<5;i++)
		{
			cin>>tmp;
			cout<<tmp<<' ';
			input(tmp,deck[i].point,deck[i].suit);
		}
		cur=0;
		//构造5张牌的全部情况,存放在sum中
		for(i=0;i<=5;i++)//手牌中选i张
			structure(i,0,0,hand,temp);
		int best=1;
		for(i=0;i<32;i++)
		{
			int t=solve(sum[i]);
			if(t>best) best=t;
			if(best==9) break;
		}
		cout<<"Best hand: ";
		switch(best)
		{
			case 1:cout<<"highest-card"<<endl;break;
			case 2:cout<<"one-pair"<<endl;break;
			case 3:cout<<"two-pairs"<<endl;break;
			case 4:cout<<"three-of-a-kind"<<endl;break;
			case 5:cout<<"straight"<<endl;break;
			case 6:cout<<"flush"<<endl;break;
			case 7:cout<<"full-house"<<endl;break;
			case 8:cout<<"four-of-a-kind"<<endl;break;
			case 9:cout<<"straight-flush"<<endl;break;
		}
	}
	return 0;
}

你可能感兴趣的:(UVa 131)