*(中等) dp HOJ 2133 Tourist

本文介绍了一种使用动态规划解决迷宫问题的方法,旨在找到从左上角到右下角并返回,途中经过最多特定位置的路径。通过定义状态和转移方程,实现了高效的求解。

Tourist

My Tags  (Edit)
Source : Nordic Collegiate Programming Contest 2004
Time limit : 3 secMemory limit : 32 M

Submitted : 54, Accepted : 29

A lazy tourist wants to visit as many interesting locations in a city as possible without going one step further than necessary. Starting from his hotel, located in the north-west corner of city, he intends to take a walk to the south-east corner of the city and then walk back. When walking to the south-east corner, he will only walk east or south, and when walking back to the north-west corner, he will only walk north or west. After studying the city map he realizes that the task is not so simple because some areas are blocked. Therefore he has kindly asked you to write a program to solve his problem.

Given the city map (a 2D grid) where the interesting locations and blocked areas are marked, determine the maximum number of interesting locations he can visit. Locations visited twice are only counted once.

Input

The first line in the input contains the number of test cases (at most 20). Then follow the cases. Each case starts with a line containing two integers, W and H (2 <= W, H <= 100), the width and the height of the city map. Then follow H lines, each containing a string with W characters with the following meaning:

  • '.' Walkable area
  • '*' Interesting location (also walkable area)
  • '#' Blocked area

    You may assume that the upper-left corner (start and end point) and lower-right corner (turning point) are walkable, and that a walkable path of length H + W - 2 exists between them.

    Output

    For each test case, output a line containing a single integer: the maximum number of interesting locations the lazy tourist can visit.

    Sample Input

    2
    9 7
    *........
    .....**#.
    ..**...#*
    ..####*#.
    .*.#*.*#.
    ...#**...
    *........
    5 5
    .*.*.
    *###.
    *.*.*
    .###*
    .*.*.
    

    Sample Ouput

    7
    8
    


这道题算是学到了新思路了,原来迷宫可以这样dp的。。。。

题意:给出一个迷宫,从左上角开始走到右下角,然后从右下角走到左上角,要经过尽可能多的*,往下走的时候只能向右或向下走,回去的时候只能向上走和向左走。

思路:其实这样相当于从起点走出两条路使得两条路经过的*的总和最多。我们用dp[i][j][k] 表示第i条斜线(45度),第一个点在第j列,第二个点在第k列,所能达到的最大值。那么转移方程是dp[i][j][k] = max(dp[i-1][j-1][k],dp[i-1][j][k-1],dp[i-1][j-1][k-1],dp[i-1][j][k])+w;

代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
#define mp make_pair
#define max(a,b) (a) < (b) ? (b) : (a)
#define LL long long
#define eps 1e-8

const int maxn = 210;
char maze[maxn][maxn];
int dp[2][maxn][maxn];
int n , m;
void init()
{
memset(dp,0,sizeof(dp));
memset(maze,0,sizeof(maze));
}

void input()
{
scanf("%d%d",&m,&n);
for (int i = 1 ; i <= n ; ++i) scanf("%s",maze[i]+1);
}

inline int max4(int a,int b,int c,int d)
{
if (a > b) b = a;
if (b > c) c = b;
if (c > d) d = c;
return d;
}

inline int to_row(int i,int j)
{
return i-j+1;
}

void solve()
{
int i;
for (i = 1 ; i < n+m ; ++i)
{
memset(dp[i%2],0,sizeof(dp[i%2]));
for (int j = 1 ; j <= m ; ++j)
{
int r1 = to_row(i,j) , c1 = j;
if (maze[r1][c1]=='#' || maze[r1][c1]==0) continue;
for (int k = 1 ; k <= m ; ++k) 
{
int r2 = to_row(i,k) , c2 = k;
if (maze[r2][c2]=='#' || maze[r2][c2]==0) continue;
int w = 0;
if (maze[r1][c1]=='*') ++w;
if (maze[r2][c2]=='*' && j!=k) ++w;
dp[i%2][j][k] = max4(dp[(i+1)%2][j-1][k],dp[(i+1)%2][j][k-1],
 dp[(i+1)%2][j-1][k-1],dp[(i+1)%2][j][k])+w;
}
}
}
printf("%d\n",dp[(i+1)%2][m][m]);
}

int main()
{
int T; cin>>T;
while (T--)
{
init();
input();
solve();
}
}


题后语:有时候,从终点回来和起点过去其实没什么不同。换个角度想,终点可能是起点,起点可能也是终点。但是我们渴望的仍然是那个遥远的终点。。。因为人人总能看到起点,所以起点总被人嫌弃。。。起点也是一个很美的状态,像恋爱就是。。。。呵呵 ,是吧。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值