本文共 2704 字,大约阅读时间需要 9 分钟。
这篇文章主要讨论了一种名为“13面值”的问题,涉及如何分配13种不同的面值物品。文章从问题的抽象开始,介绍了两种不同的转换方式,并详细解释了状态转移的过程。最后,作者提供了一个C++代码实现,用于计算满足条件的分配方式数。
文章结构清晰,技术细节丰富,适合对动态规划和递归算法感兴趣的读者。以下是对文章的优化和重写版本:
在这个问题中,我们需要计算将n个物品分配到13种不同的面值中,每种面值最多可以有4个物品。为了简化问题,我们引入了一个递归动态规划的方法,通过维护状态转移矩阵来解决问题。
我们可以将问题抽象为一个四维数组f[l1][l2][l3][l4],其中:
这种状态转移方式虽然直观,但维度较高,导致状态转移逻辑复杂。
为了简化状态,我们引入了一个变量las(Last Assigned Species),表示上一次选择的物品种类剩下的数量。这种方法将状态维度从四维降低到五维,具体形式为f[l1][l2][l3][l4][las]。
需要注意的是,当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)); }}
通过上述方法,我们成功地将问题转化为一个递归动态规划问题,通过维护状态转移矩阵,能够高效地计算满足条件的分配方式数。这种方法在处理类似的问题时具有较高的扩展性和适用性。
转载地址:http://xnrfk.baihongyu.com/