首先构建DFS搜索的函数:long long DFS(long long n, long long m, long long liquor)。这里n代表已经遇到店的次数,m代表已经遇到花的次数,liquor代表当前李白有多少酒。然后设N、M为李白需要遇到店和花的次数,针对每次的n、m、liquor三个参数,根据以下规则进行剪枝:
1、遇到店和花的次数都不能超限;
2、酒空时不能遇花,即liquor的范围与花一致,都在[0,M];
3、当遇完所有店时,壶中liquor需与剩余遇花数(M-m)一致;
4、确保最后一次遇到花且酒空,此时n和m应该达到上限;
5、最后遇到的花,不存在中途酒空的情况。
以上剪枝可能复杂了些,但出于考虑到避免出现越界等运行错误,因此实现全部约束参考代码如下:
if (n == N && m == M && liquor == 0) return 1; else if (m == M && n < N) return 0; else if (n == N && (M - m) > liquor) return 0; else if (n > N || m > M) return 0; else if (liquor < 0 || liquor > M) return 0; else if (liquor == 0 && (n != N && m != M)) return 0;
然后给出DFS的状态转移方程:DFS(n,m,liquor) = DFS(n+1,m,liquor*2) + DFS(n,m+1,liquor-1)。
基于该状态转移方程和剪枝只拿到了48分,因此引入一个三维记忆数组,DP[N][M][M],用于记录DFS的每种状态,如果已经计算过该状态则直接返回数组对应下标的元素值,如果没有计算过该状态则按DFS的方法计算该状态并将结果保存在记忆数组中。从而避免了重复计算状态引发的时间损耗,让时间复杂度从O(2^(N+M))降低为O(N*M^2),虽然还是三次方级别的,但是通过本题已经绰绰有余了。最终合并上述思路,给出代码:
#include <iostream> using namespace std; long long N, M; long long dp[150][150][150]; long long DFS(long long n, long long m, long long liquor); int main() { cin >> N >> M; for (int i = 0; i < 150; i ++) for (int j = 0; j < 150; j ++) for (int k = 0; k < 150; k ++) dp[i][j][k] = -1; cout << DFS(0, 0, 2) % 1000000007 << endl; return 0; } long long DFS(long long n, long long m, long long liquor) { long long num = 0; if (n == N && m == M && liquor == 0) return 1; else if (m == M && n < N) return 0; else if (n == N && (M - m) > liquor) return 0; else if (n > N || m > M) return 0; else if (liquor < 0 || liquor > M) return 0; else if (liquor == 0 && (n != N && m != M)) return 0; if (dp[n][m][liquor] != -1) return dp[n][m][liquor]; num = (num + DFS(n, m + 1, liquor - 1)) % 1000000007; num = (num + DFS(n + 1, m, liquor * 2)) % 1000000007; dp[n][m][liquor] = num; return num; }
需要特别的是,”if (dp[n][m][liquor] != -1)“该语句块必须写在剪枝下面,否则没有剪枝的保护n可能会大于N从而导致数组的指针越界(其他变量也一样)。采用这种方法就可以通过全部用例。运行结果如下:
这种损耗空间来换取时间的方式在竞赛和考试中很常用。
0.0分
11 人评分
DNA (C++代码)浏览:671 |
C语言程序设计教程(第三版)课后习题5.7 (C语言代码)浏览:1045 |
C语言程序设计教程(第三版)课后习题8.2 (Java代码)浏览:2287 |
C语言程序设计教程(第三版)课后习题1.5 (C++代码)浏览:1114 |
C语言训练-大、小写问题 (C语言代码)浏览:792 |
C语言程序设计教程(第三版)课后习题9.10 (C语言代码)浏览:866 |
字符串的输入输出处理 (C语言代码)浏览:1085 |
陈教主的三角形 (C语言代码)浏览:1196 |
C语言程序设计教程(第三版)课后习题1.5 (C语言代码)浏览:497 |
C语言程序设计教程(第三版)课后习题9.8 (C语言代码)浏览:604 |