dp迷宫计数

1.

传送门

我们有一个网格,水平有H行,垂直有W列的正方形。如果Sij是#,则为wall;如果Sij是..,则为road。在正方形(1,1)有一个王后,即国际象棋中的棋子。在一次移动中,它可以向右、向下或斜向右下角移动任意数量的方块,而不需要跳过墙方块。皇后从方格(1,1)移动到方格(H,W)有多少种方式?求模数(1e9+7)。
在这里,两种旅行方式被认为是不同的,当且仅当存在i使得第i步后女王的位置在这两种方式中不同。

意思就是说可以向下,向右,或斜向右下角移动任意步,问你从(1,1)到(n,m)有种多少方式

这个题就是设置三个数组,类似于前缀和

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=2000+100;
ll dp[maxn][maxn];
ll xie[maxn][maxn];
ll up[maxn][maxn];
ll l[maxn][maxn];
char a[maxn][maxn];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%s",a[i]+1); 
    }
    dp[1][1]=1;
    l[1][1]=up[1][1]=xie[1][1]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i==1&&j==1){
                continue;
            }
            if(a[i][j]=='#'){
                dp[i][j]=l[i][j]=xie[i][j]=up[i][j]=0;
            }
            else{
                dp[i][j]=(up[i-1][j]+xie[i-1][j-1]+l[i][j-1])%mod;
                up[i][j]=(up[i-1][j]+dp[i][j])%mod; 
                l[i][j]=(l[i][j-1]+dp[i][j])%mod;
                xie[i][j]=(xie[i-1][j-1]+dp[i][j])%mod;
            } 
        }
    }
    printf("%lld
",dp[n][m]);
} 

设有 n×m的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。

Input

第一行有两个整数 n,m

接下来 n 行每行 m 个整数,依次代表每个方格中的整数。

Output

一个整数,表示小熊能取到的整数之和的最大值。

Samples

Input Copy
3 4
1 -1 3 2
2 -1 4 -1
-2 2 -3 -1
Output
9
Input Copy
2 5
-1 -1 -3 -2 -7
-2 -1 -4 -1 -2
Output
-10

Hint

样例1解释:

按上述走法,取到的数之和为1+2+(-1)+4+3+2+(-1)+(-1)=9,可以证明为最大值。

注意,上述走法是错误的,因为第2行第2列的方格走过了两次,而根据题意,不能经过已经走过的方格。

另外,上述走法也是错误的,因为没有走到右下角的终点。

样例2解释:

按上述走法,取到的数之和为(-1)+(-1)+(-3)+(-2)+(-1)+(-2)=-10,可以证明为最大值。因此,请注意,取到的数之和的最大值也可能为负数。

数据范围:

  • 对于 20%20% 的数据,n,m5
  • 对于 40%40% 的数据,n,m50
  • 对于 70%70%的数据,n,m300
  • 对于 100%100%的数据,1n,m1e3。方格中整数的绝对值不超过 104104。

Source

2020 CSP J2

这个肯定是dp

就是设置三个数组

ll l[maxn][maxn];
ll up[maxn][maxn];
ll down[maxn][maxn];
分别代表从左边,从上边,从下边更新的最大值
一定要一列,一列的更新
要不然那个向从下边的没法更新
在更新每一类的时候要先正着跟新一边,再倒着更新一边
转移方程是:
up[i][j]=max(l[i-1][j],up[i-1][j])+a[i][j];
l[i][j]=max(l[i][j-1],max(up[i][j-1],down[i][j-1]))+a[i][j];
down[i][j]=max(l[i+1][j],down[i+1][j])+a[i][j];
 
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=2e3+100;
typedef long long ll;
const ll INF=-1e18;
ll a[maxn][maxn];
ll l[maxn][maxn];
ll up[maxn][maxn];
ll down[maxn][maxn];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            l[i][j]=up[i][j]=down[i][j]=INF;
        }
    }
    l[1][1]=up[1][1]=down[1][1]=a[1][1];
    for(int j=1;j<=m;j++){
        for(int i=1;i<=n;i++){
            if(i!=1){
                up[i][j]=max(l[i-1][j],up[i-1][j])+a[i][j];
            }
            if(j!=1){
                l[i][j]=max(l[i][j-1],max(up[i][j-1],down[i][j-1]))+a[i][j];
            }
        }
        for(int i=n-1;i>=1;i--){
            down[i][j]=max(l[i+1][j],down[i+1][j])+a[i][j];
        }
    }
    cout<<max(up[n][m],l[n][m])<<endl; 
}
原文地址:https://www.cnblogs.com/lipu123/p/13999751.html