題目大意:
給兩個長度相等的數字串s1,s2。每次操作可以把連續的最多三位都+1或-1,如果超過9則變成0,如果小於0則變成9.問從s1到s2最少的步數。
解題思路:
每一位移動正確最多5位,如果一位一位的移動最多需要1000*5=5000 。
長度有1000太大,不能直接用BFS。
因為每次改變最多只影響3位,前面的i-3位不改變,所以可以設dp[i][j][k]表示處理到了第i位,且最後兩位分別為j,k時,前面的i-2位為原串s1時,達到最終的s2的前i位時移動的最小的步數。
轉移時,先把第i位移動正確,然後枚舉在移動第i位時,前面兩位可能到達的狀態,此時第i-2位移動的步數要小於等於第i-1位的,第i-1位的要小於等於第i位的,然後根據dp[i-1]的狀態更新dp[i]的狀態。
比如有三位分別需要移動2 3 4位 第3位需要移動4位,在移動第3位時,可以先都移動2位,然後再後兩位移動1位,最後一位再移動一位。
這類的dp做的比較少,以後多分析各種狀態。
代碼:
<SPAN style="FONT-SIZE: 14px">#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
#define Maxn 1100
//最多只有1000*5
int dp[Maxn][12][12]; //dp[i][x][y]表示處理到了當前i位,且最後兩位是x和y的,轉到最後的i位所需的最小步數
int a[Maxn],b[Maxn];
char sa[Maxn];
int main()
{
while(~scanf("%s",sa))
{
int n=strlen(sa);
for(int i=1;i<=n;i++)
a[i]=sa[i-1]-'0';
scanf("%s",sa);
for(int i=1;i<=n;i++)
b[i]=sa[i-1]-'0';
memset(dp,INF,sizeof(dp));
dp[0][0][0]=0;
for(int i=1;i<=n;i++)
{
for(int x=0;x<=9;x++)
{
if(i==1&&x) //只有1位的話全部處理為x=0的情況
continue;
for(int y=0;y<=9;y++)
{
int up=(b[i]-y+10)%10; //當前位一定要達到要求
int dow=(y-b[i]+10)%10;
if(i==1) //此時x一定為0
dp[i][x][y]=min(up,dow);
else if(i==2)
{
int xx=0; //i-2位置為0,表示只有一位的情況
for(int j=0;j<=up;j++) //正轉
{
int yy=(x+j)%10; //在當前位達到要求時,前面一位最多可以移動up位
dp[i][x][y]=min(dp[i][x][y],dp[i-1][xx][yy]+up);
}
for(int j=0;j<=dow;j++) //反轉
{
int yy=(x-j+10)%10;
dp[i][x][y]=min(dp[i][x][y],dp[i-1][xx][yy]+dow);
}
}
else //枚舉 操作第i位up或dow時,第i-1位和第i-2位能夠到達的狀態
{
for(int j=0;j<=up;j++) //2 3 4 先三個移動2 再後面兩個移動1 最後一個再移動1
for(int p=j;p<=up;p++) //必須滿足第i-1位移動的大於等於第i-2位,
{
int xx=(a[i-2]+j)%10;
int yy=(x+p)%10;
dp[i][x][y]=min(dp[i][x][y],dp[i-1][xx][yy]+up);
}
for(int j=0;j<=dow;j++)
for(int p=j;p<=dow;p++)
{
int xx=((a[i-2]-j)+10)%10;
int yy=(x-p+10)%10;
dp[i][x][y]=min(dp[i][x][y],dp[i-1][xx][yy]+dow);
}
}
}
}
}
if(n==1)
printf("%d\n",dp[1][0][a[1]]);
else
printf("%d\n",dp[n][a[n-1]][a[n]]);
}
return 0;
}
</SPAN>