牌型种数问题--二维动态规划解决(附DFS)

0x01.问题

小明被劫持到X赌城,被迫与其他3人玩牌。  
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。  
这时,小明脑子里突然冒出一个问题:  
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

请填写该整数,不要填写任何多余的内容或说明文字。

注:该题是蓝桥杯2015初赛第7题,为填空题。

0x02. 分析问题

要求组合的种数,我们首先要清楚扑克牌在题目中的特点:

  1. 不计花色,只计点数。
  2. 一个点数的可能有五种,即有0,1,2,3,4五种可能。
  3. 总共拿到手的牌有13张。

于是我们的暴力枚举法就诞生了,方法就是13个for循环,每个循环都从0到4,最内层的条件是所有牌的总数为13。

这个耗时似乎有点长,在我的电脑上大概耗时3秒。

当然,这个肯定不是这个问题的最好解决办法,我发现,用动态规划可以巧妙的解决这个问题。

0x03.动态规划

动态规划(Dynamic Programming)这个简介就不说了,说白了就是,在有一定初始条件的情况下,根据一些递推的关系式,不断的往前或者往后推导,最后得到想要的答案。

运用动态规划,需要满足两个条件:

  1. 有一定的初始条件。
  2. 能找到合适的递推关系式。

0x04.动态规划解决此问题

首先,我们应该确定的是采用何种结构去把这个问题表示清楚。

13张牌,拿到每一张牌后,手中的手牌数有13种可能,我们可以用二维数组表示出这个关系:

DP[i][j]  表示拿到第 i 张牌,此时手中有 j 张牌的可能组合数。

寻找初始条件:很明显,初始条件就是,拿到第一张牌的时候,手中最多有4张牌,组合是都是1。

也就是  DP[1][0]=DP[1][1]=DP[1][2]=DP[1][3]=DP[1][4]=0。

递推条件就是,根据手中牌的数目,加上之前相同手牌数的可能组合数,然后加上'''加上这张牌能够对前一次手牌的解数产生影响的解数'''。

最终的答案就是 DP[13][13] 的值。

0x05.代码

#include<stdio.h>

int main()
{
	int i, j;
	long DP[14][14];
	for (i = 1; i <= 13; i++)
	{
		for (j = 0; j <= 13; j++)
		{
			DP[i][j] = 0;
		}
	}
	for (i = 0; i <= 4; i++)//动态规划的初始条件
	{
		DP[1][i] = 1;
	}
	for (i = 2; i <= 13; i++)
	{
		for (j = 0; j <= 13; j++)
		{
			DP[i][j] += DP[i - 1][j];//加上同牌数解数
			if (j >= 1)
			{
				DP[i][j] += DP[i - 1][j - 1];//加上一张牌的解数
				if (j >= 2)
				{
					DP[i][j] += DP[i - 1][j - 2];//加上两张牌的解数
					if (j >= 3)
					{
						DP[i][j] += DP[i - 1][j - 3];//加上三张牌的解数
						if (j >= 4)
						{
							DP[i][j] += DP[i - 1][j - 4];//加上四张及以上的解数
						}
					}
				}
			}
		}
	}
	printf("%ld", DP[13][13]);//最终解
}

答案是:3598180

0x06.附--其它解法--DFS

深度优先搜索的解法如下:


#include<stdio.h>
int ans = 0, sum = 0;
void DFS(int cur)//cur为手中牌数
{
    if (sum>13)return;
    if (cur == 13)
    {
        if (sum == 13)ans++;
        return;
    }
    else
    {
      for (int i = 0; i < 5; i++)
        {
            sum += i;
            DFS(cur + 1);
            sum -= i;//还原状态
        }
    }
}

int main()
{

    DFS(0);
    printf("%d",ans);
}

  • 36
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 多段图的最短路径问题可以使用动态规划法来解决动态规划法是一问题分解成子问题并逐步求解的方法,可以有效地解决复杂的最优化问题。 在多段图的最短路径问题中,我们需要找到从起点到终点的最短路径。这个问题可以分解成多个子问题,每个子问题都是从当前节点到终点的最短路径。我们可以从终点开始,逐步向起点推导出每个子问题的最优解,最终得到整个问题的最优解。 具体来说,我们可以定义一个二维数组dp,其中dp[i][j]表示从节点i到节点j的最短路径长度。我们从终点开始,将dp数组初始化为0,然后逐步向起点推导出每个节点的最短路径长度。具体的推导方法如下: 1. 对于终点j,dp[i][j]=0。 2. 对于最后一段的节点i,dp[i][j]=w(i,j),其中w(i,j)表示从节点i到节点j的边权。 3. 对于其他节点i,dp[i][j]=min{dp[i][k]+w(i,j)},其中k是i的后继节点。 最终,dp[1][n]就是整个问题的最优解。 需要注意的是,多段图的最短路径问题只适用于有向无环图。如果图中存在环路,那么就无法使用动态规划法来解决。 ### 回答2: 多段图最短路径问题是指通过一个有向无环图,从源点出发,到达终点,使得路径上所有边权的和最小。多段图最短路径问题与最短路径问题的区别在于多段图中有不止一个可能的路径,而且每段路径有一个权值,要求在选择路径时,使得所有路径的权值和最小。为了求解这个问题,常使用动态规划法。 动态规划的基本思想是将问题划分为若干个阶段,每个阶段都有一组状态,计算每个阶段的最优值,通过推导每个状态的最优值,逐步得到问题的整体最优解。对于多段图最短路径问题动态规划的过程如下: 1. 定义状态:设f[i][j]为顶点i到终点j的最短路径长度,定义有k段路程S={s_1,s_2,…,s_k},其中s_1=i,s_k=j。 2. 状态转移方程:对于每一段路程s_t=(x,y),f[x][j]表示从x点出发到终点j的最短路径长度,由此可以得到转移方程:f[x][j]=min{f[y][j]+w[x,y]}。 3. 边界条件:对于终点j,f[j][j]=0。 4. 求解问题:最终结果为f[i][j]。 在使用动态规划解决多段图最短路径问题时,需要进行自底向上的迭代计算,从最后一段路程开始,每次计算当前段的每个起点的最短路径,最后得到整个图的最短路程。 总之,动态规划法是解决多段图最短路径问题的有效方法,通过划分阶段、定义状态、建立状态转移方程和考虑边界条件,能够高效解决问题,适用于实际工作中的路径规划和出行问题。 ### 回答3: 多段图的最短路径问题是指在由多个阶段构成的有向加权图中,从一个起点到达终点的最短路径问题。这问题在很多实际问题中经常出现,如物流运输、城市规划等方面都需要对多段图的最短路径进行求解动态规划作为一有效并且广泛使用的求解多段图最短路径问题算法,具有以下几个步骤: 第一步:将图分为多个阶段。 第二步:定义状态。状态的定义要根据问题的实际情况来定,例如以第i个点为起点到第j个点为终点时的最短路径长度为状态。 第三步:推导状态转移方程。对于每一个阶段 i,求解出从起点到达该阶段所有点的最短路径,然后根据这个结果推导出到达下一个阶段 i+1 所要经过的边的最短路径。状态转移方程的求解可以使用贪心策略,即对于每个状态,选择到达下一个阶段的费用最小的路径。 第四步:求解最优解。最终的目标是要找到从起点到终点的最短路径长度,因此可以通过求解从起点到达终点的最短路径长度来实现。 在实现上,我们可以先将多段图表示为邻接矩阵或邻接表的形式,然后逐个按照阶段进行求解。在求解的过程中需要使用记录表来记录每个点的最短路径以及最短路径长度,以便于后面的状态转移方程的计算和最优解的求解。 总结:多段图的最短路径问题是一个经典的动态规划问题,其求解需要进行多个阶段的计算和状态转移方程的推导,通过实现在动态规划算法框架下,可以求得最短路径长度,为实际问题求解提供了非常有力的工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值