题意:从左上顶点开始,到右下顶点结束,求最短路径上的最大权值。 |
动态规划思路(递归法):
其实题目简化了问题,看出来了就好做很多。
题目说要路径最短,那肯定不能往回走,每一步要么向下要么向右,这样其实就很好写状态转移方程了,如果用递推法的话,状态转移方程为
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;
}