题目:
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;
}