SOJ 2818 QQ音速 (DP)
2015-10-23 07:51
288 查看
@(K ACMer)
题意:
两个手指按在方向键上,每次变换手指的位置会有相应地花费,给你一个需要按的方向键的序列,问你完成这些序列所需要对最小花费是多少?
分析:
拿到这道题首先想暴力搜索的方法:dfs(x, i, j),表示当前在字符串的x位,左手放在i位置,右手放在j位置走到结尾需要对步数.然后就可以很容易写一个复杂度为O(2n)的dfs了.
显然要TLE啦~,这里有很多重复计算的,开个DP数组把已经算过的记录下来,这就叫记忆优化搜索,其本质就是DP,只不过是递归的实现,转化为循环实现就是标准的DP了.这个题递归的实现不能过因为,其递归次数过多,会爆栈!
定义状态为:dp[k][i][j]为在移动到序列的第k位,左手放在i位置,右手放在j位置所需的最小花费.然后该状态由其子状态dp[k - 1][t][j]或者dp[k - 1][i][t]转移而来(注意这里的t值得是str[k - 1],因为你的上一次必须放在正确的位置.),,转移方程如下.
dp[k][i][j]=min(dp[k−1][t][j]+w[t][i],dp[k−1][i][t]+w[t][j])
总结:
DP并不是来就是瞎猜方程,而是要先从最暴力的方法优化过来,其核心实现就是把已经计算过的不要重复计算,也就是记忆优化.递推方程要把该问题,转移到其子问题上
code:
先上比较直观的记忆优化搜索的代码:
DP的代码:
题意:
两个手指按在方向键上,每次变换手指的位置会有相应地花费,给你一个需要按的方向键的序列,问你完成这些序列所需要对最小花费是多少?
分析:
拿到这道题首先想暴力搜索的方法:dfs(x, i, j),表示当前在字符串的x位,左手放在i位置,右手放在j位置走到结尾需要对步数.然后就可以很容易写一个复杂度为O(2n)的dfs了.
显然要TLE啦~,这里有很多重复计算的,开个DP数组把已经算过的记录下来,这就叫记忆优化搜索,其本质就是DP,只不过是递归的实现,转化为循环实现就是标准的DP了.这个题递归的实现不能过因为,其递归次数过多,会爆栈!
定义状态为:dp[k][i][j]为在移动到序列的第k位,左手放在i位置,右手放在j位置所需的最小花费.然后该状态由其子状态dp[k - 1][t][j]或者dp[k - 1][i][t]转移而来(注意这里的t值得是str[k - 1],因为你的上一次必须放在正确的位置.),,转移方程如下.
dp[k][i][j]=min(dp[k−1][t][j]+w[t][i],dp[k−1][i][t]+w[t][j])
总结:
DP并不是来就是瞎猜方程,而是要先从最暴力的方法优化过来,其核心实现就是把已经计算过的不要重复计算,也就是记忆优化.递推方程要把该问题,转移到其子问题上
code:
先上比较直观的记忆优化搜索的代码:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; int n; const int maxn = (int)1e6 + 200; char str[maxn]; int w[4][4] ={{0, 1, 2, 2}, {1, 0, 1, 1}, {2, 1, 0, 2}, {2, 1, 2, 0}}; int dp[4][4][maxn]; int dfs(int x, int a, int b, int v) { if (x == n) return v; if (dp[a][b][x] != -1) return dp[a][b][x]; int key = str[x] - '0'; return dp[a][b][x] = min(dfs(x + 1, key, b, w[a][key]), dfs(x + 1, a, key, w[b][key])) + v; } int main(void) { while (~scanf("%s", str)) { n = strlen(str); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { for (int k = 0; k < n; k++) { dp[i][j][k] = -1; } } } memset(dp, -1, sizeof(dp)); printf("%d\n", dfs(0, 2, 3, 0)); } return 0; }
DP的代码:
#include <cstdio> #include <cstring> using namespace std; int n; const int maxn = (int)1e6 + 200, INF = 0x3fffffff; char str[maxn]; int w[4][4] ={{0, 1, 2, 2}, {1, 0, 1, 1}, {2, 1, 0, 2}, {2, 1, 2, 0}}; int dp[maxn][4][4]; #define mins(x, y) (x) < (y) ? (x) : (y) int main(void) { while (scanf("%s", str) == 1) { n = strlen(str); for (int i = 0 ;i < 4; i++) { for (int j = 0; j < 4; j++) { dp[0][i][j] = w[2][i] + w[3][j]; } } for (int k = 1; k <= n; k++) { for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { // if (k < n && str[k] - '0' != i && str[k] - '0' != j) continue; int t = str[k - 1] - '0'; dp[k][i][j] = mins(dp[k - 1][t][j] + w[t][i], dp[k - 1][i][t] + w[t][j]); } } } int ans = INF; for (int i = 0; i < 4; i++) { ans = mins(ans, dp [i][str[n - 1] - '0']); ans = mins(ans, dp [str[n - 1] - '0'][i]); } printf("%d\n", ans); } return 0; }
相关文章推荐
- soj 2785 Binary Partitions (构造类似完全背包)
- AsyncTask的使用
- C++异常处理
- linux硬件级虚拟机系统 电脑安桌游戏多开完全去除vm标识去虚拟化
- Leetcode NO.252 Meeting Rooms
- Search in Rotated Sorted Array II
- 151022总结
- 反射
- LeetCode Word Pattern
- 黑马程序员-OC回顾-对象特性
- 由欲从编程菜鸟突破到中级选手遇到的瓶颈想到的
- C#如何实现单例启动和关闭全部窗体
- 网络编程
- 全新 GNOME Games:一款应用驾驭所有游戏
- 黑马程序员-构造函数以及构造函数的重写
- Permutations II
- Permutations
- vim配置文件解析
- 【软考5】解释型 or 编译型
- 【软考5】解释型 or 编译型