DP--划分问题(掷骰子)
2016-07-01 17:05
288 查看
一次掷n个骰子,每个骰子有p个面,问有多少种情况?
要考虑重复情况,例:2个骰子,3个面,1,1,2和2,1,1是一种情况对于这种情形
我们一般进行排序处理 把所有情况所对应的数从小到大排序
a1<=a2<=a3<=...<=an。
比如1,1,2和2,1,1就相当于1,1,2了
再比如 3,1,2 2,3,1 都相当于1,2,3
这样每种情况都与一个序列一一对应不是吗?
方法一:
和划分问题一类似,考虑动态规划方程
第一个骰子为1时,剩下的骰子有p
个面选择,f(n-1,p)
第一个骰子为2时,剩下的骰子有p-2个面选择,f(n-1,p-1)
……
第一个骰子为p时,剩下的骰子有1
个面选择,f(n-1,1)
所以得到f(n,p)=f(n-1,p)+f(n-1,p-2)+……+f(n-1,1)
由上式可以推出f(n,p-1)=f(n-1,p-2)+f(n-1,p-3)+……+f(n-1,1)
两式联立得递推公式
f(n,p)=f(n-1,p)+f(n,p-1)
当n==1时,f(n,p)=p;当p==1时,f(n,p)==1。
//DP数组记忆化
int DP(int n,int p)
{
if(n==1)return p;
else if(p==1) return 1;
int dp[n+1][p+1]={1},i,j;
for(i=1;i<=n;i++)
for(j=1;j<=p;j++)
{
if(i==1) dp[i][j]=j;
else if(j==1) dp[i][j]=1;
else dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
return dp
[p];
}
//递归
int f(int n,int p)
{
if(n==1) return p;
else if(p==1) return 1;
else return f(n,p-1)+f(n-1,p);
}
方法二:
[b]以p个面分别出现的次数为参照,[b]n个骰子,每个骰子有p个面
那么我们只要知道这p个面 每个面出现了多少次,依据上述的排序规则 这个序列就确定了[/b]
然后就转化成了一个方程
x1+x2+x3+...xp=n 有多少组非负整数解
(xi代表第i个面出现了多少次)
对于这个方程 我们令ai=xi+1
则x1+x2+x3+...xp=n的非负数解与方程 a1+a2+a3+...ap=n+p的正数解一一对应
a1+a2+a3+...ap=n+p 这个方程的正数有多少组解呢? 答案是C(n+p-1,p-1)种
因为可以看成是有n+p个1 然后中间插入p-1个板子 隔板法求得方程的解数
所以一次掷n个骰子,每个骰子有p个面 有C(n+p-1,p-1)种情况.[/b]
//计算组合数C(n,m)
int C(int n,int m)
{
if(m>n/2) m=n-m;
double result=1;
int i=n,j=m,t;
while(i>=n-m+1||j>=1)
{
if(i>=n-m+1)
{
result*=(i*1.0);
i--;
}
if(j>=1)
{
result/=(j*1.0);
j--;
}
}
return (int)result;
}
int Formula(int n,int p) // C(n+p-1,p-1)
{
return C(n+p-1,p-1);
}
相关文章推荐
- C++动态规划之最长公子序列实例
- C++动态规划之背包问题解决方法
- C#使用动态规划解决0-1背包问题实例分析
- 详解Android应用中屏幕尺寸的获取及dp和px值的转换
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- 使用C语言求解扑克牌的顺子及n个骰子的点数问题
- LFC1.0.0 版本发布
- 动态规划
- Android dpi,dip,dp的概念以及屏幕适配
- 子网掩码的划分
- C++ 动态规划
- 子网的划分详解
- Android px、dp、sp之间相互转换
- 老生常谈,再说子网划分
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- ip的划分(非常详细)
- android中像素单位dp、px、pt、sp的比较
- 动态规划解决背包问题的核心思路