HDU 4433 locker 状态压缩DP
2014-09-11 00:48
435 查看
题意:给出一个长度最长为1000的数字序列,像密码锁一样,你可以上下滑动,同时会0-9的循环。每次操作,最多对连续的三个数字操作。现在给出起始序列和目标序列,求出最少的操作次数,从起始序列到目标序列。
思路:刚开始,感觉像八数码问题一样,是图的隐式搜索,但是,计算后发现,图的点的数目太多。必须要转换思路。最后没想出来。
看了网上的题解后,才知道,原来像状态压缩的八皇后问题一样,对于每个操作,其实只会影响前后三个数字,其他的位的数字是不用考虑的。
我们也没有必要随便乱转,从前往后,给操作一个序(这个序在DP中很重要),对于前面已经转到目标序列的数字,我们就没有必要再考虑了。
进一步优化: 如果保存三位数字,同时在加上长度,计算复杂度会发现,照样会TLE。我们再仔细思考,可以发现,对于三个数字中最左边的数字,我们必须一次性将其旋转到目标序列的对应的数字。要不然,后面将无法递推。
这样,整个DP就是三维的了。
dp[i][j][k]表示处理完前i位,使第i+1为j,第i+2位为k,最少的操作次数。在状态转移的过程中,我们暴力枚举每个可能出现的情况即可。具体的转移方程看代码吧。
复杂度:1000 * 10 * 10 * 10 * 10 = 10^7 符合要求
代码如下:
学姿势:
1.预处理需要的数据。
2.对于超过范围的处理,我们可以添加合法的数据,增大范围。
思路:刚开始,感觉像八数码问题一样,是图的隐式搜索,但是,计算后发现,图的点的数目太多。必须要转换思路。最后没想出来。
看了网上的题解后,才知道,原来像状态压缩的八皇后问题一样,对于每个操作,其实只会影响前后三个数字,其他的位的数字是不用考虑的。
我们也没有必要随便乱转,从前往后,给操作一个序(这个序在DP中很重要),对于前面已经转到目标序列的数字,我们就没有必要再考虑了。
进一步优化: 如果保存三位数字,同时在加上长度,计算复杂度会发现,照样会TLE。我们再仔细思考,可以发现,对于三个数字中最左边的数字,我们必须一次性将其旋转到目标序列的对应的数字。要不然,后面将无法递推。
这样,整个DP就是三维的了。
dp[i][j][k]表示处理完前i位,使第i+1为j,第i+2位为k,最少的操作次数。在状态转移的过程中,我们暴力枚举每个可能出现的情况即可。具体的转移方程看代码吧。
复杂度:1000 * 10 * 10 * 10 * 10 = 10^7 符合要求
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 1100; int up[15][15]; int down[15][15]; char s[MAX],t[MAX]; int dp[MAX][11][11]; void init() {//可能出现的转的情况提前计算 for(int i = 0 ; i <= 9; ++i) for(int j = 0; j <= 9; ++j){ up[i][j] = (j - i + 10) % 10; down[i][j] = (i - j + 10) % 10; } } int main(void) { //freopen("input.txt","r",stdin); init(); while(scanf("%s%s",s,t) != EOF){ int n = strlen(s); s = s[n+1] = t = t[n+1] ='0';//为了处理方便,多加两个元素 for(int i = 0; i < n + 2; ++i) s[i] -= '0',t[i] -= '0'; memset(dp,0x3f,sizeof(dp)); dp[0][s[0]][s[1]] = 0;//除了最初的序列,其他的dp都没有合法值 for(int i = 1; i <= n; ++i){//从i到n递推 for(int j = 0; j <= 9; ++j){//枚举两位数字的每一位 for(int k = 0; k <= 9; ++k){ int t1 = up[j][t[i-1]];//将三位中最左边的数字向上转到目标序列需要的操作 for(int u = 0; u <= t1; ++u)//枚举可能出现的操作 for(int v = 0; v <= u; ++v) dp[i][(k + u) % 10][(s[i+1] + v) % 10] = min(dp[i][(k + u) % 10][(s[i+1] + v) % 10], dp[i-1][j][k] + t1); int t2 = down[j][t[i-1]];//将三位中最左边的数字向下转到目标徐磊需要的操作 for(int u = 0; u <= t2; ++u)//枚举可能出现的操作 for(int v = 0; v <= u; ++v) dp[i][(k - u + 10) % 10][(s[i+1] - v + 10) % 10] = min(dp[i][(k - u + 10) % 10][(s[i+1] - v + 10) % 10], dp[i-1][j][k] + t2); } } } printf("%d\n",dp [0][0]); } return 0; }
学姿势:
1.预处理需要的数据。
2.对于超过范围的处理,我们可以添加合法的数据,增大范围。
相关文章推荐
- HDU 4433 类似于状态压缩的DP
- HDU 4433 类似于状态压缩的DP
- HDU 4049 Tourism Planning 状态压缩(DP)
- HDU 1074 状态压缩DP
- hdu 4317 Unfair Nim (状态压缩DP) 【2012 Multi-University Training Contest 2】
- Hdu 4057 Rescue the Rabbit (AC自动机+状态压缩dp) - 2011 ACM-ICPC Dalian Regional Contest Problem G
- HDU 4336 Card Collector [状态压缩概率DP]
- hdu 4317 Unfair Nim(状态压缩DP)——2012 Multi-University Training Contest 2
- HDU_4317 Unfair Nim 状态压缩dp
- HDU 3811 DP状态压缩
- hdu 4385 Moving Bricks (状态压缩dp 2012 Multi-University Training Contest 9 )
- HDU 3920 Clear All of Them I 状态压缩DP 2011 Multi-University Training Contest 9 - Host by BJTU
- hdu 1565 状态压缩 dp
- HDU 3001 Travelling 【状态压缩DP】
- hdu 1074 DFS+状态压缩DP
- hdu 2809 God of War //状态压缩DP
- HDU 4049 状态压缩DP
- hdu 3811 用状态压缩DP 解决看似组合数学的题目
- HDU 3811 Permutation 记忆化搜索 状态压缩 DP
- hdu 1074 Doing Homework 状态压缩的DP