$[HihoCoder] P1159$ 题解
从l1到l2: 从l2到l3: 从l3到l4: 从l4到l5:
发布日期:2025-06-07 18:04:18
浏览次数:3
分类:精选文章
本文共 2704 字,大约阅读时间需要 9 分钟。
这篇文章主要讨论了一种名为“13面值”的问题,涉及如何分配13种不同的面值物品。文章从问题的抽象开始,介绍了两种不同的转换方式,并详细解释了状态转移的过程。最后,作者提供了一个C++代码实现,用于计算满足条件的分配方式数。
文章结构清晰,技术细节丰富,适合对动态规划和递归算法感兴趣的读者。以下是对文章的优化和重写版本:
13面值问题的解决方法
在这个问题中,我们需要计算将n个物品分配到13种不同的面值中,每种面值最多可以有4个物品。为了简化问题,我们引入了一个递归动态规划的方法,通过维护状态转移矩阵来解决问题。
第一种转换方式
我们可以将问题抽象为一个四维数组f[l1][l2][l3][l4],其中:
- l1表示剩下1种面值的物品个数
- l2表示剩下2种面值的物品个数
- l3表示剩下3种面值的物品个数
- l4表示剩下4种面值的物品个数
这种状态转移方式虽然直观,但维度较高,导致状态转移逻辑复杂。
第二种转换方式
为了简化状态,我们引入了一个变量las(Last Assigned Species),表示上一次选择的物品种类剩下的数量。这种方法将状态维度从四维降低到五维,具体形式为f[l1][l2][l3][l4][las]。
状态转移方程
- f[l1][l2][l3][l4][3] += l1 * f[l1-1][l2][l3][l4][1] * 1
- f[l1][l2][l3][l4][3] += l2 * f[l1+1][l2-1][l3][l4][2] * 2
- f[l1][l2][l3][l4][4] += l3 * f[l1][l2+1][l3-1][l4][3] * 3
- f[l1][l2][l3][l4][4] += l4 * f[l1][l2][l3+1][l4-1][4] * 4
需要注意的是,当las=2时,需要减去1,以避免选择相同的物品种类。
递归动态规划实现
我们通过递归函数Dfs来实现状态转移:
#includeusing namespace std;#define int unsigned long longint read() { int f = 1, w = 0; char x = 0; while (x < '0' || x > '9') { if (x == '-') f = -1; x = getchar(); } while (x != EOF && x > '0' && x < '9') { w = (w < 3) ? (w < 1 ? 1 : w + 1) : (w < 1 ? 1 : w + 1) + (x - '0'); x = getchar(); } return w * f;}int Dfs(int l1, int l2, int l3, int l4, int las) { if (!(l1 | l2 | l3 | l4)) return 1; if (f[l1][l2][l3][l4][las]) return f[l1][l2][l3][l4][las]; int ans = 0; if (l1) { ans += (l1 != las) ? Dfs(l1 - 1, l2, l3, l4, 1) : 0; } if (l2) { ans += (l2 != las) ? Dfs(l1 + 1, l2 - 1, l3, l4, 2) * 2 : 0; } if (l3) { ans += (l3 != las) ? Dfs(l1, l2 + 1, l3 - 1, l4, 3) * 3 : 0; } if (l4) { ans += l4 * Dfs(l1, l2, l3 + 1, l4 - 1, 4) * 4; } return f[l1][l2][l3][l4][las] = ans;}int main() { #ifndef ONLINE_JUDGE freopen("Text1.in", "r", stdin); #endif int T = read(); for (int Itst = 1; Itst <= T; Itst++) { int n = read(); int c[14] = {0}, num[5] = {0}; printf("Case #%llu: ", Itst); for (int i = 1; i <= n; i++) { char s[5]; scanf("%s", s); if (s[0] >= '0' && s[0] <= '9') { c[s[0] - '0']++; } else { switch(s[0]) { case 'T': c[10]++; break; case 'J': c[11]++; break; case 'Q': c[12]++; break; case 'K': c[13]++; break; case 'A': c[1]++; break; } } } for (int i = 1; i <= 13; i++) { num[c[i]]++; } printf("%llu\n", Dfs(num[1], num[2], num[3], num[4], 0)); }}
总结
通过上述方法,我们成功地将问题转化为一个递归动态规划问题,通过维护状态转移矩阵,能够高效地计算满足条件的分配方式数。这种方法在处理类似的问题时具有较高的扩展性和适用性。
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2026年06月05日 17时38分03秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP 实现N阶矩阵相乘
2023-02-28
php 延迟静态绑定static关键字
2023-02-28
Redis入门
2023-02-28
PHP 截取字符串乱码的解决方案
2023-02-28
php 接口类与抽象类的实际作用
2023-02-28
PHP 插入排序 -- 折半查找
2023-02-28
PHP 支持8种基本的数据类型
2023-02-28
php 放大镜,放大镜放大图片效果
2023-02-28
PHP 数据库连接池实现
2023-02-28
php 数组 区别,PHP中数组的区别
2023-02-28
PHP 数组怎么添加一个元素
2023-02-28
PHP 文件操作
2023-02-28
php 文字弹幕效果代码,HTML5文字弹幕效果
2023-02-28
php 时间日期函数,获取今天开始时间,结束时间
2023-02-28
php 标准规范
2023-02-28
PHP 浮点型精度运算相关问题
2023-02-28
php 浮点型计算精度问题
2023-02-28
php 特定时间段统计,jpgraph某个时间段的数据统计
2023-02-28
php 生成csv mac下乱码
2023-02-28
php 生成证书 签名及验签
2023-02-28