题目描述
shopee的办公室非常大,小虾同学的位置坐落在右上角,而大门却在左下角,可以把所有位置抽象为一个网格(门口的坐标为0,0),小虾同学很聪明,每次只向上,或者向右走,因为这样最容易接近目的地,但是小虾同学不想让自己的boss们看到自己经常在他们面前出没,或者迟到被发现。他决定研究一下如果他不通过boss们的位置,他可以有多少种走法?
输入描述:
第一行 x,y,n (0<x<=30, 0<y<=30, 0<=n<= 20) 表示x,y小虾的座位坐标,n 表示boss的数量( n <= 20)
接下来有n行, 表示boss们的坐标(0<xi<= x, 0<yi<=y,不会和小虾位置重合)
x1, y1
x2, y2
……
xn, yn
输出描述:
输出小虾有多少种走法
示例1
输入
3 3 2
1 1
2 2
输出
4
题目解析
这道题是走方格的升级版,但也不过就是加了个障碍而已,难度还是很简单的,不过,这里使用dfs递归会超时,所以只能转而采用动态规划思路实现。
- 第一步:划分子问题
求解的是到(x,y)有多少条路径,那么在求解过程中一定需要知道到达(i,j)(i<=x,j<=y)有多少条路经,子问题很容易找到了吧。 - 状态转移方程
dp【i】【j】表示的是到(i,j)这个点有多少条路径,没什么好解释的,自然而然得出该结论
dp【i+1】【j】=dp【i+1】【j】+dp【i】【j】
表示的含义是:到达(i+1,j)点数目包括从下方这个点(i,j)的所有路径
dp【i】【j+1】=dp【i】【j+1】+dp【i】【j】
表示的含义是:到达(i,j+1)点数目包括从左方这个点(i,j)的所有路径 - 填表
为了最大程度节省空间,我们令障碍(i,j)的dp【i】【j】=-1,那么当求解释,遇到障碍直接跳过
初始化:dp【i】【j】={0}
到达(0,0)点只有一条路径,所以dp【0】【0】=1
注意!一定令dp数组定义为long long型,因为数组几乎成斐波那契数列这样增长的,所以速度超快的
接下来就是代码实现
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<utility>
#include<cmath>
#include<limits.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
ll dp[31][31];
int n;
int main() {
int x,y;
while(scanf("%d%d%d",&x,&y,&n)!=EOF){
memset(dp,0,sizeof(dp));
int xt,yt;
dp[0][0]=1;
while(n--){
scanf("%d%d",&xt,&yt);
dp[xt][yt]=-1;
}
dp[0][0]=1;
for(int i=0;i<=x;i++){
for(int j=0;j<=y;j++){
if(dp[i][j]==-1){
continue;
}
if(j<y&&dp[i][j+1]!=-1){
dp[i][j+1]+=dp[i][j];
}
if(i<x&&dp[i+1][j]!=-1){
dp[i+1][j]+=dp[i][j];
}
}
}
printf("%lld\n",dp[x][y]);
}
return 0;
}