Matrix Maze HihoCoder - 1702 DP Solution

#1702 : Matrix Labyrinth

Time limit: 10000ms
Single point time limit: 1000ms
Memory Limit: 256MB

describe

Given an NxN lattice matrix maze, each lattice has an integer A ij . Initially, little Hi is located in the grid A 11 in the upper left corner of the maze . He can move to the right or down with each step, and the goal is to move to the exit of the maze - A NN in the lower right corner .  

The cost that small Hi needs to pay includes the sum of the integers in all the grids passed in the path, as well as the cost to change the moving direction.  

The cost of Xiao Hi's first change of direction is 1, the cost of the second time is 2, the cost of the third time is 4, and the cost of the Kth time is 2 K-1 .  

Please help Xiao Hi figure out the path with the least cost to leave the maze, and output the cost to pay.

enter

The first line contains an integer N. (1≤N≤100)  

The following N lines each contain N integers representing matrix A. (1 ≤ A ij  ≤ 100)

output

The minimum cost of the path from the upper left corner to the lower right corner.

sample input
3  
1 3 5  
1 1 2  
5 1 1
Sample output
9

The meaning of the question: Find the minimum cost sum (including the cost of changing direction and the cost of passing coordinates) on the road from the upper left corner to the lower right corner (only to the right or down),

The cost of changing direction the first time is 1, the cost of the second time is 2, the cost of the third time is 4, ... the cost of the Kth time is 2 K-1
Ideas: Because you can only go right or down, you need to think about dynamic programming, coordinates, directions, and the number of turns.

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);
}




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325971348&siteId=291194637