合工大oj 1307 散步

13年安徽省赛题目。bfs处理出所有点到n,m点的最短距离,再dfs一次即可。

ps:在bfs时,加入v数组若i,j点已经在栈中则不必入栈,更新距离即可。避免重复入栈导致超时。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
#define N 100
#define INF 1000000000
typedef long long LL;
int n, m;
LL dp[N][N];
int a[N][N];
int dis[N][N];
int v[N][N];
int s[1000000][2];
int ntr;
int ptr;
int mov[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
void init(){
    memset(dp, 0, sizeof(dp));
    memset(dis, -1, sizeof(dis));
    memset(v, 0, sizeof(v));
    ptr = 0;
    ntr = 0;
}
void bfs(int i, int j){
    for(int l = 0; l < 4; l ++){
        int i0, j0;
        i0 = i + mov[l][0];
        j0 = j + mov[l][1];
        if(i0 < 1 || j0 < 1 || i0 > n || j0 > m)continue;
        if(dis[i0][j0] == -1 || (dis[i][j] + a[i0][j0] < dis[i0][j0])){
            dis[i0][j0] = dis[i][j] + a[i0][j0];
            if(!v[i0][j0]){
                s[ptr][0] = i0;
                s[ptr][1] = j0;
                v[i0][j0] = 1;
                ptr ++;
            }
        }
    }
}
LL dfs(int i, int j){
    if(dp[i][j]) return dp[i][j];
    LL ans = 0;
    for(int l = 0; l < 4; l ++){
        int i0, j0;
        i0 = i + mov[l][0];
        j0 = j + mov[l][1];
        if(i0 < 1 || j0 < 1 || i0 > n || j0 > m)continue;
        if(dis[i0][j0] < dis[i][j]) {
            ans += dfs(i0, j0);
        }
    }
    return dp[i][j] = ans;
}
int main(){
    while(scanf("%d%d", &n, &m) != EOF){
        init();
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%I64d", &a[i][j]);
            }
        }
        dis[n][m] = 0;
        s[ptr][0] = n;
        s[ptr][1] = m;
        v[n][m] = 1;
        ptr ++;
        while(ntr < ptr){
            bfs(s[ntr][0], s[ntr][1]);
            v[s[ntr][0]][s[ntr][1]] = 0;
            ntr ++;
        }
        dp[n][m] = 1;
        printf("%I64d\n", dfs(1, 1));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值