程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> dp hdu-4433 locker

dp hdu-4433 locker

編輯:C++入門知識

題目大意:

給兩個長度相等的數字串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>

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved