HDU 4433 locker 2012 Asia Tianjin Regional Contest 状态压缩DP
2014-10-16 15:37
148 查看
题意:给出一个长度最长为1000的数字序列,像密码锁一样,你可以上下滑动,同时会0-9的循环。每次操作,最多对连续的三个数字操作。现在给出起始序列和目标序列,求出最少的操作次数,从起始序列到目标序列。
想这道题花了一天的时间,我认为是道很难的DP。这个阶段很好划分,对于前面完成的密码锁就不再考虑。问题的关键是这个旋转每次可以的情况很多。
同时也可以发现当I位置上确定移好后,至多影响到后两位,-> dp[i][j][k] 表示当前i位移好后,i+1 为j , i+2为k 的次数。
这里同时使用一个预处理技巧,对于一个移动操作,有向上向下两种。当将一个值转到另一个值,up[i][j]=(j-i+10)%10;down[i][j]=(i-j+10)%10; i->j 的方法
在dp中必然会有对于阶段的描述,一般从1开始,表达每一段。这里为了求dp
[0][0] 在最后再补上两位。
这两句话是我刚开始一直困惑的地方。首先要明确转移方程是阶段间的转移dp[i-1][...][...]->dp[i][...][...]
这样看,配合②我们发现当dp[i-1][j][k]已知,dp[i][...][...]是将其 j转为t[i-1]。(这个是理解的关键)。这里的u,v表明的是在j转为t[i-1]过程中,后两位的改变情况枚举值。
dp[i][(k+u)%10][(s[i+1]+v)%10] 这个现在就可以理解了,对于dp[i-1]的j 现在dp[i]考虑的就是上次的K了。
还有一点就是标号很乱一会是阶段的i,一会又是起始位置.......
想这道题花了一天的时间,我认为是道很难的DP。这个阶段很好划分,对于前面完成的密码锁就不再考虑。问题的关键是这个旋转每次可以的情况很多。
同时也可以发现当I位置上确定移好后,至多影响到后两位,-> dp[i][j][k] 表示当前i位移好后,i+1 为j , i+2为k 的次数。
这里同时使用一个预处理技巧,对于一个移动操作,有向上向下两种。当将一个值转到另一个值,up[i][j]=(j-i+10)%10;down[i][j]=(i-j+10)%10; i->j 的方法
在dp中必然会有对于阶段的描述,一般从1开始,表达每一段。这里为了求dp
[0][0] 在最后再补上两位。
dp[0][s[0]][s[1]]=0;刚开始0阶段,一个都未完成的时候,即前0次移好i+1,i+2位为这样的次数为0
int r=up[j][t[i-1]];//① dp[i][(k+u)%10][(s[i+1]+v)%10]=min(...)//②
这两句话是我刚开始一直困惑的地方。首先要明确转移方程是阶段间的转移dp[i-1][...][...]->dp[i][...][...]
这样看,配合②我们发现当dp[i-1][j][k]已知,dp[i][...][...]是将其 j转为t[i-1]。(这个是理解的关键)。这里的u,v表明的是在j转为t[i-1]过程中,后两位的改变情况枚举值。
dp[i][(k+u)%10][(s[i+1]+v)%10] 这个现在就可以理解了,对于dp[i-1]的j 现在dp[i]考虑的就是上次的K了。
还有一点就是标号很乱一会是阶段的i,一会又是起始位置.......
#include <stdio.h> #include <string.h> #include <map> #include <iostream> #define inf 0x3fffffff const int maxn=1010; typedef unsigned __int64 ull; using namespace std; char s[maxn],t[maxn]; int dp[maxn][10][10]; int up[10][10],down[10][10]; int min(int a,int b) { return a<b?a:b; } void init() { int i,j; for(i=0;i<10;i++) for(j=0;j<10;j++) { up[i][j]=(j-i+10)%10; down[i][j]=(i-j+10)%10; } } int main() { init(); while(~scanf("%s%s",s,t)) { memset(dp,0x3f,sizeof(dp)); int i,j,k,u,v; int n=strlen(s); s =s[n+1]=t =t[n+1]=0; for(i=0;i<n;i++) s[i]-='0',t[i]-='0'; dp[0][s[0]][s[1]]=0;//除了最初的序列,其他的dp都没有合法值 for(i=1;i<=n;i++) { for(j=0;j<10;j++)//枚举两位数字的每一位 { for(k=0;k<10;k++) { int r=up[j][t[i-1]];//从j转到t[i-1]的次数,将三位中最左边的数字向上转到目标序列需要的操作 for(u=0;u<=r;u++)//枚举可能出现的操作 { for(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] + r); } r=down[j][t[i-1]]; for(u=0;u<=r;u++) for(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] + r); } } } printf("%d\n",dp [0][0]); } return 0; }
相关文章推荐
- HDU 4433 locker(DP)(2012 Asia Tianjin Regional Contest)
- HDU 4433 locker 2012 Asia Tianjin Regional Contest 减少国家DP
- HDU 4433 locker 状态压缩DP
- HDU 4433 locker(12年天津,DP)
- hdu 4433 locker(动态规划:枚举状态)
- hdu 4433 locker
- HDU 4433 locker(SPFA+DP)
- hdu 4433 locker (dp)
- hdu 4433 locker(DP,4级)
- HDU 4433 locker(三维dp)
- HDU 4433 locker(12年天津,DP)
- Hdu 4433 locker【思维+Dp】
- hdu 4433 locker(DP,4级)
- HDU 4433 locker(DP)( UVA 1631 - Locker)
- hdu 4433—— locker
- ACM/ICPC 2012 天津 - HDU 4433 - DP(顺推)
- HDU 4433 locker(DP)
- ACM练级日志:HDU 4433 Locker
- hdu 4433 locker(DP)
- HDU 4433 locker