100가지 동적 계획 – 8UVA 1631 Locker 추이, 상태 정의 및 상태 전환 방정식

솔직히 이 문제를 풀지 못했습니다. 풀지 못한 이유는 적당한 상태를 정의하지 못했기 때문입니다. 물론입니다. 이 상태를 생각해도 상태 이동 방정식을 생각하면 또 다른 일입니다. 경험을 쌓는 것으로 하겠습니다.
사실 나중에 생각해 보니 이 상태는 정의가 정말 좋았고 최우수자 구조와 무후효성을 만족시킨 다음에 추이를 통해 계산할 수 있었다.자세를 더 올려야지!
정의 상태 dp[i][x][y]는 현재 i위로 넘어갔고 i+1위는 x, i+2위는 y이며 전 i-1위는 이미 넘어간 최소 비용을 의미한다.
i위 x와 i+1위의 값 y를 일일이 열거한 다음에 우리가 i위를 복원하려면 (aim[i]-x+10)%10번 돌려야 한다. 그러면 i위를 돌리는 과정에서 i+1위와 i+2위는 모두 따라 회전할 수 있다. 그러나 구속 조항 하나가 바로 i위의 회전 횟수>=i+1위의 회전 횟수>=i+2위의 회전 횟수>= i+2위의 회전 횟수,따라서 이어서 i+1위의 회전 횟수와 i+2위의 회전 횟수를 매거하면 된다.
가설 i+1위가 j회, i+2위가 k회(k<=j)
그러면 상태 이동 방정식은 dp[i][(y+j)%10][(orgin[i+2]+k)%10]=min(dp[i][(y+j)%10][(orgin[i+2]+k)%10], dp[i-1][x][y]+(aim[i]-x+10)%10);//orgin은 원래의 직렬, x, y에 이미 제시되었음을 나타낸다
그러나 우리는 위에서 한 방향만 고려했고, 또 한 방향의 고려 방법은 위와 완전히 같다. 단지 회전 횟수는 10-(b[i]-x+10)%10일 뿐이다.
다음은 코드입니다.
#include 
#include 
#include 

using namespace std;  
  
const int N=12,M=1005;  
  
char s[M],t[M];  
int orgin[M],aim[M],dp[M][N][N],len;  
  
int main()  
{  
    while (scanf("%s%s",s,t)!=EOF){      
        len=strlen(s);  
        for(int i=1;i<=n;++i)
        	orgin[i]=s[i-1]-'0',aim[i]=t[i-1]-'0';  
        orgin[n+1]=aim[n+1]=orgin[n+2]=aim[n+2]=0;
        memset(dp,0x3f,sizeof dp);    
        dp[0][orgin[1]][orgin[2]]=0;  
        for(int i=1;i<=n;++i)
        for(int x=0;x<=9;++x)
        for(int y=0;y<=9;++y){  
            int d=(aim[i]-x+10)%10;  
            for(int j=0;j<=d;++j)
           	for(int k=0;k<=j;++k)  
            	dp[i][(y+j)%10][(orgin[i+2]+k)%10]=min(dp[i][(y+j)%10][(orgin[i+2]+k)%10],dp[i-1][x][y]+d);  

            int p=10-d;  
            for(int j=0;j<=p;++j)
           	for(int k=0;k<=j;++k) 
          		dp[i][(y-j+10)%10][(orgin[i+2]-k+10)%10]=min(dp[i][(y-j+10)%10][(orgin[i+2]-k+10)%10],dp[i-1][x][y]+p);  
        }  
        printf("%d
",dp[n][0][0]); } }

Dalao 의 코드에 감사 드립니다.http://blog.csdn.net/bobodem/article/details/50285441

좋은 웹페이지 즐겨찾기