(DP) UVA 10913 Walking on a Grid

题面
我好菜啊T_T

题目大意:
给你一个N*N的网格,你只能向左、右或向下移动,且每个格子最多只能进入一次。需要你从 ( 1 , 1 ) (1, 1) (1,1) 移动到 ( N , N ) (N, N) (N,N)
每个格子中都有一个整数p,要求最多经过k个负数格,且到达(N, N)时,所经过格子的和最大。

由于进入一个格子有三种状态(从上方、左侧或右侧进入),每种状态各对应一类路径,我们应当分开记录,因此我们需要一个三维数组 d p [ x ] [ y ] [ f r o m ] dp[x][y][from] dp[x][y][from]

同时考虑到经过的负权格不能超过K,于是可以在再拓展一维用来记录经过的负权格数。由此我们得到一个数组 d p [ x ] [ y ] [ k ] [ f r o m ] dp[x][y][k][from] dp[x][y][k][from]

代码如下

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <deque>
#include <queue>
#include <set>
#include <cstring>
#include <cmath>
#include <string>
#include <ctime>
#define ll long long
clock_t _timer_start,_timer_end;
void start_timer(){_timer_start=clock();}
void stop_timer(){
    _timer_end=clock();
    double dur=(double)(_timer_end-_timer_start);
    printf("Time Consume:%lf second\n", dur/CLOCKS_PER_SEC);
}

const int inf=0x3f3f3f3f;
const double dinf=1e300;
const ll linf=0x3f3f3f3f3f3f3f3f;

using namespace std;

const int maxn=0;

int dp[100][100][10][5];
int val[100][100];
int vis[100][100];//用来判断是否已经访问过该点
int aans;

int N,K;
inline bool check(int r,int c){//检查是否(r,c)越界
    if(r>0 && c>0 && r<=N && c<=N)return true;
    return false;
}

//from
//0:来自左 1:来自右 2:来自上
int delta[3][2]={{0, 1}, {0, -1}, {1, 0}};
void dfs(int r, int c, int k, int from, int ans){
    k+=val[r][c]<0;
    if(k>K) return;
    dp[r][c][k][from] = ans + val[r][c];
    if(r==N && c==N){
        aans = max(aans, dp[r][c][k][from]);
        return;
    }
    vis[r][c]=1;//避免多次经过同一点
    for(int i=0;i<3;i++){
        int x=r+delta[i][0];
        int y=c+delta[i][1];
        if(!check(x, y))continue;
        if(!vis[x][y] && dp[x][y][k+(val[x][y]<0)][i]<dp[r][c][k][from]+val[x][y]){
            dfs(x, y, k, i,dp[r][c][k][from]);
        }
    }
    vis[r][c]=0;

}

void solve(){
    int kase=0;
    while(scanf("%d%d", &N,&K)==2 && (N || K)){
        memset(dp, -0x3f, sizeof dp);
        memset(vis, 0, sizeof vis);
        aans = dp[1][1][1][1];
        int mark=aans;
        for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) scanf("%d", &val[i][j]);
        dfs(1, 1, 0, 2, 0);
        printf("Case %d: ",++kase);
        if(aans != mark)
            printf("%d\n", aans);
        else
            printf("impossible\n");
    }
}

#define debug 1
int main(){
    #if debug == 1

    #endif
    solve();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值