您的位置:首页 > 其它

[HDU 4433]locker[DP]

2013-10-06 13:50 381 查看
题意:

给出密码做的现状和密码, 每次可以移动连续的最多3列, 向上或向下, 求将密码调出来所需要的最少步数.

思路:

首先应看出,恢复的过程中, 调每一位的时间顺序是不影响的, 不妨就从左到右一位位消除.

dp[ i ][ x ][ y ] 表示前 i 位已经消除为0, 且其后的两位为x,y时, 所需要的最小操作数.

每次可以旋转1~3位, 注意旋转3位时, 第三位和第二位的约束关系.[因此而wa了...]

和Wordstack那道题的"题解版"的思路相同, 用已知的状态去更新未知的状态.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
int dp[MAXN][10][10], bit[MAXN], n;
char s[MAXN], t[MAXN];
int main()
{
while(~scanf("%s %s",s,t))
{
n = strlen(s);
for(int i=0;i<n;i++)
bit[i+1] = (t[i]+10-s[i]) % 10;
bit[n+1] = bit[n+2] = 0;
memset(dp,0x3f,sizeof(dp));
dp[0][bit[1]][bit[2]] = 0;
for(int i=0;i<n;i++)
for(int x=0;x<10;x++)
for(int y=0;y<10;y++)
if(dp[i][x][y]!=INF)
{
dp[i+1][y][bit[i+3]]
= min(dp[i+1][y][bit[i+3]],
dp[i][x][y] + min(x,10-x));//1
for(int j=1;j<=x;j++)
{
dp[i+1][(y+10-j)%10][bit[i+3]]
= min(dp[i+1][(y+10-j)%10][bit[i+3]],
dp[i][x][y] + x);//2
for(int k=1;k<=j;k++)
dp[i+1][(y+10-j)%10][(bit[i+3]+10-k)%10]
= min(dp[i+1][(y+10-j)%10]
[(bit[i+3]+10-k)%10],
dp[i][x][y] + x);
}
for(int j=1;j<=10-x;j++)
{
dp[i+1][(y+j)%10][bit[i+3]]
= min(dp[i+1][(y+j)%10][bit[i+3]],
dp[i][x][y] + 10-x);//2
for(int k=1;k<=j;k++)
dp[i+1][(y+j)%10][(bit[i+3]+k)%10]
= min(dp[i+1][(y+j)%10][(bit[i+3]+k)%10],
dp[i][x][y] + 10-x);
}
}
printf("%d\n",dp
[0][0]);
}
}


话说...这是组队以来我做的第一道非水题.....对我而言的非水题吧......

DP还是比较有意思的, 要多多练习~ orz
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: