使用C语言求解扑克牌的顺子及n个骰子的点数问题
扑克牌的顺子
问题描述:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2-10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
思路:可以将这5张牌排个序,然后统计出0的个数以及非0数字之间的间隔数,如果出现重复的非0数字,那么不是顺子。如果间隔数小于等于0的个数,那么是顺子。暂时未想到更好的办法。
参考代码:
//函数功能:从扑克牌中随机抽5张牌,判断是不是一个顺子
//函数参数:pCards为牌,nLen为牌的张数
//返回值:是否顺子
boolIsContinuous(int*pCards,intnLen)
{
if(pCards==NULL||nLen<=0)
returnfalse;
sort(pCards,pCards+nLen);//调用标准库的排序算法
inti;
intzeroCount=0;//大小王用0表示
intcapCount=0;//间隔数
//统计0的个数
for(i=0;i<nLen;i++)
{
if(pCards[i]==0)
zeroCount++;
else
break;
}
//统计间隔数
intpreCard=pCards[i];
for(i=i+1;i<nLen;i++)
{
intcurCard=pCards[i];
if(preCard==curCard)//与前一张牌比较
returnfalse;
else
capCount+=curCard-preCard-1;//累加间隔数
preCard=curCard;
}
return(zeroCount>=capCount)?true:false;//只要王的个数大于间隔数
}
n个骰子的点数
问题描述:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。
思路:这是一道应用动态规划思想的题目,而动态规划最难的就是要找最优子结构。并采取一种称为备忘录的方法避免重复计算。因为备忘录方法为每个解过的子问题建立了备忘录,以备需要时参看,避免了相同子问题的重复求解。
本题的最优子结构为:F(k,n)表示k个骰子点数和为n的种数,k表示骰子个数,n表示k个骰子的点数和
/=F(k-1,n-6)+F(k-1,n-5)+F(k-1,n-4)+F(k-1,n-3)+F(k-1,n-2)+F(k-1,n-1)对于k>0,k<=n<=6*k F(k,n)= \=0对于n<korn>6*k
当k=1时,F(1,1)=F(1,2)=F(1,3)=F(1,4)=F(1,5)=F(1,6)=1。
从上面公式可以看出,k个骰子点数和为n的种数只与k-1个骰子的和有关。这就可以用到备忘录的方法,用一张表格保存已解决的子问题的解,然后自底向上填表。考虑到当前层的计算只与下一层有关,因此只需保存一行。
参考代码:
constintFACE_NUM=6;//骰子的面数
//函数功能:n个骰子的点数
//函数参数:number为骰子数
//返回值:无
voidPrintSumProbabilityOfDices(intnumber)
{
if(number<=0)
return;
int*pSum=newint[number*FACE_NUM+1];//和的种类
doubletotal=pow(6.0,number);//<cmath>
intsize=number*FACE_NUM;
inti,j,k;
//初始化
pSum[0]=0;
for(i=1;i<=FACE_NUM;i++)
pSum[i]=1;
for(;i<=size;i++)
pSum[i]=0;
for(i=2;i<=number;i++)//骰子个数从2到n
{
for(j=i*FACE_NUM;j>=i;j--)//第i个骰子的和的范围为[i,i*FACE_NUM]
{
pSum[j]=0;
for(k=1;k<=6&&j>=k;k++)//其实展开就是F(i,j)=F(i-1,j-6)+F(i-1,j-5)+F(i-1,j-4)+F(i-1,j-3)+F(i-1,j-2)+F(i-1,j-1)
{
pSum[j]+=pSum[j-k];
}
}
//不可能的情况,即i个骰子的和不可能小于i
for(j=i-1;j>=0;j--)
pSum[j]=0;
}
//打印结果
for(i=0;i<=size;i++)
cout<<"sum="<<i<<",p="<<pSum[i]/total<<endl;
}