矩陣迷宮 HihoCoder - 1702 DP解法

#1702 : 矩陣迷宮

時間限制:10000ms
單點時限:1000ms
內存限制:256MB

描述

給定一個NxN的方格矩陣迷宮,每個格子中都有一個整數Aij。最初小Hi位於迷宮左上角的格子A11,他每一步可以向右或向下移動,目標是移動到迷宮的出口——右下角ANN。  

小Hi需要支付的代價包括路徑中經過的所有格子中的整數之和,以及改變移動方向需要支付的代價。  

小Hi第一次改變方向的代價是1,第二次的代價是2,第三次的代價是4,…… 第K次的代價是2K-1。  

請你幫小Hi算出要離開迷宮代價最小的路徑,並輸出要支付的代價。

輸入

第一行一個整數N。  (1 ≤ N ≤ 100)  

以下N行每行N個整數,代表矩陣A。  (1 ≤ Aij ≤ 100)

輸出

從左上角到右下角路徑的最小的代價。

樣例輸入
3  
1 3 5  
1 1 2  
5 1 1
樣例輸出
9

題意:求從左上角到右下角(只能向右或者向下走)經過的路上的最小代價和(包括改變方向的代價,和經過的座標的代價),

第一次改變方向的代價是1,第二次的代價是2,第三次的代價是4,…… 第K次的代價是2K-1。 
思路:因爲只能向右或者向下走,所以要往動態規劃上想,座標,方向,和拐彎的次數。

dp【i】【j】【k】【h】表示到座標(i,j)這個位置,並且當前的方向爲k(0表示下,1表示右),已經轉彎h次的最小代價。

(這個代價先不包括h次轉彎,最後再算)。

一共分爲四種情況,面朝下向下走,面朝右向下走,面朝下向右走,面朝右向右走;

計算到dp[n][n][2][20]爲止, 因爲n*n的圖,不能往回走,所以一定經過2*n-1個座標,這些座標代價最大2*100*100,所以拐彎代價不會很大,及2*20就遠遠大於座標代價的極限值了。數組最後一維算到20足以。

代碼:

#include <iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 200500
#define LL long long
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
int a[105][105];
int dp[105][105][2][23];
int minn(int x,int y)
{
    return x>y?y:x;
}
int main()
{
    mem(dp,inf);//初始化爲極限大
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            scanf("%d",&a[i][j]);
    dp[1][1][1][0]=dp[1][1][0][0]=a[1][1];//初始座標
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            for(int h=0; h<20; h++)//開始狀態轉移
            {
                if(i<n)//如果不爲最後一行,那麼就可以往下走
                {
                    if(dp[i][j][0][h]!=inf)//當前位置代價不爲極限大的話
                        dp[i+1][j][0][h]=minn(dp[i+1][j][0][h],dp[i][j][0][h]+a[i+1][j]);//面朝下向下走一格,不需要轉向
                    if(dp[i][j][1][h]!=inf)
                        dp[i+1][j][0][h+1]=minn(dp[i+1][j][0][h+1],dp[i][j][1][h]+a[i+1][j]);//面朝右向下走一格,要轉向
                }
                if(j<n)//如果可以向右走的話
                {
                    if(dp[i][j][0][h]!=inf)
                        dp[i][j+1][1][h+1]=minn(dp[i][j+1][1][h+1],dp[i][j][0][h]+a[i][j+1]);//面朝下向右走,要轉向
                    if(dp[i][j][1][h]!=inf)
                        dp[i][j+1][1][h]=minn(dp[i][j+1][1][h],dp[i][j][1][h]+a[i][j+1]);//面朝右向右走,不用轉向
                }
            }
    int ans=inf;
    for(int i=0; i<=20; i++)
    {
        ans=minn(ans,dp[n][n][0][i]+(1<<i)-1);//遍歷終點的所有情況,存最小值
        ans=minn(ans,dp[n][n][1][i]+(1<<i)-1);//最後計算拐彎i次的代價
    }
    printf("%d\n",ans);
}




發佈了156 篇原創文章 · 獲贊 56 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章