#1702 : 矩陣迷宮
描述
給定一個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);
}