【10687 東方迷宮】 SCAU 新生賽題解

在這裏插入圖片描述在這裏插入圖片描述

題意:從左上頂點開始,到右下頂點結束,求最短路徑上的最大權值。

動態規劃思路(遞歸法):

其實題目簡化了問題,看出來了就好做很多。
題目說要路徑最短,那肯定不能往回走每一步要麼向下要麼向右,這樣其實就很好寫狀態轉移方程了,如果用遞推法的話,狀態轉移方程爲

dp[i][j] = max(dp[i-1][j]+dp[i][j-1])+a[i][j]

即當前位置由上邊或者左邊得到,取前一個狀態的最優解即可。
最後返回dp[n][n]。
同時注意當前元素和要選的元素之間有沒有障礙

我這裏用遞歸寫,
用三維數組dp[i][j][pos]表示當前位置(i,j)由上個位置經pos(往右,往下)操作過來的狀態。這樣寫的好處就是在兩個位置之間如果有障礙的話,可以提前標記兩個位置不能互相通過。
同時用方向數組表示向下和向右。詳見代碼。

#include <iostream>
#include <vector>
#include <cstdio>
#include <map>
#include <string>
#include <cmath>
#include <cstring>
#include <algorithm>
#define maxn 105
using namespace std;
static int inf =0x3f3f3f3f;
typedef  long long ll;
ll dp[maxn][maxn][4] ;  //maxn*maxn  grid  and  2 directions
ll no[maxn][maxn][4];  //  some blocks
ll grid[maxn][maxn];
ll  direction[2][2] =  {{1,0},{0,1}};  // 2derections :  down and right        方向數組
int a[2][2];
ll n;
int num;
ll max(ll a, ll b)
{
    return a>b?a:b;
}
ll  DP(ll i, ll j, ll pos)
{
   // cout<<i<<' '<<j<<endl;
    if(dp[i][j][pos]!=-1)  return dp[i][j][pos];
        if(i<1||i>n||j<1||j>n)  return dp[i][j][pos]=-inf;
   if(i==n&&j==n)
    {
         return dp[i][j][pos] = grid[i][j];
    }
    // main code follows
    ll  maxone = -1;
    for(int k=0; k<2; k++)
    {
        if(no[i+direction[k][0]][ j+direction[k][1] ][k])  continue;
        maxone = max(DP(i+direction[k][0],j+direction[k][1], k)+grid[i][j],maxone);
    }
    return dp[i][j][pos] = maxone ;

}
void blocks()
{
     for(int i=1; i<=num; i++)
        {
            cin>>a[0][0]>>a[0][1]>>a[1][0]>>a[1][1];
            a[0][0]++;
            a[0][1]++;
            a[1][1]++;
            a[1][0]++;
            if(a[0][0]==a[1][0])
            {
                if(a[0][1]>a[1][1])
                {
                    int temp = a[0][1];
                    a[0][1] =  a[1][1];
                    a[1][1] = temp;
                }
               // no[a[0][0]][a[0][1]][] = 1;
                no[a[1][0]][a[1][1]][1] = 1;
            }
            else if(a[0][1]==a[1][1])
            {
                if(a[0][0]>a[1][0])
                {
                    int temp = a[0][0];
                    a[0][0] = a[1][0];
                    a[1][0] = temp;
                }
               // no[a[0][0]][a[0][1]][0] = 1;
                no[a[1][0]][a[1][1]][0] = 1;
            }
        }
}
int main()
{
    int kase;
    cin>>kase;
    int m = 1;
    while(kase--)
    {
        cin>>n;
        char c = getchar();
        memset(dp,-1,sizeof(dp));
        memset(no,0,sizeof(no));
        for(int i=1; i<=n; i++)
        {
            string s;
            getline(cin,s);
            for(int j=1; j<=n; j++)
             {
                    grid[i][j] = s[j-1] - '0';
             }
        }
        cin>>num;
        blocks();
       printf("Case %d: %lld\n",m++,DP(1,1,1));
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章