[NOIP2002 普及组] 过河卒

题目链接 https://www.luogu.com.cn/problem/P1002


 

一道入门的dp问题。

初始位置为(0,0),有点儿麻烦,改为(1,1),所以所有坐标的位置全部+1。

卒到达的每一个位置都是从此位置的上方和左方走过来的。那么假设卒从(1,1)到达此点的左方点的路径有x条,到达此点的上方点的路径有y条,则到达此点的路径有x+y条。

那么可以得到状态转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1],所以最终的答案被储存在dp[n][m](假设B的坐标为(n,m))。

需要注意的是需要对dp[1][1]或dp[2][0]进行初始化=1,否则无论走到哪个点其结果都是0。(令dp[2][1]=1按道理也是可以的,我也是这么写的)。

接下来开始循环计算到达每个点有几条路径。当遇到马和马能到达的点时就跳过。在这之前需要将马所在的点和马能到达的位置初始化,用来判断。


 

放AC代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int bx,by,mx,my;
 4 long long int dp[40][40];
 5 int s[40][40];
 6 int main()
 7 {
 8     cin>>bx>>by>>mx>>my;
 9     bx+=2; by+=2; mx+=2; my+=2;//防止越界,并且假设A点为(1,1)
10     dp[2][1]=1;
11     s[mx][my]=1;//标记马的位置以及马能到达的点
12     s[mx-2][my-1]=1; s[mx-2][my+1]=1;
13     s[mx-1][my-2]=1; s[mx-1][my+2]=1;
14     s[mx+1][my-2]=1; s[mx+1][my+2]=1;
15     s[mx+2][my-1]=1; s[mx+2][my+1]=1;
16     for(int i=2;i<=bx;i++)
17     {
18         for(int j=2;j<=by;j++)
19         {
20             if(s[i][j]) continue;//如果此点被标记则跳过
21             dp[i][j]=dp[i-1][j]+dp[i][j-1];//状态转移方程
22         }
23     }
24     cout<<dp[bx][by];
25     return 0;
26 }

 

当然,还可以优化。用滚动数组可以节省空间。

因为我们只用到第i行和第i-1行的答案,所以可以只定义dp[2][1]就好了。

如何只保留第i和第i-1行的答案?取模。i=>i%2,i-1=>(i-1)%2。

此外,因为是滚动数组 , 所以如果当前位置被马拦住了一定要记住清零。


 

另,学到了一个新知识:

x%2可以在代码中写成更快的运算方式x&1。

如果x是偶数,那么x&1=0,如果x是奇数,那么x&1=1。

 

测试了一下:

拿给出的第五个测试点来说,即输入14 16 7 5(我怎么知道的?蛤蛤,因为我又出现鲨臂错误啦!)。

用codeblocks跑出来:%2为3.348s;&1为3.117s。(um...一点点也是快啦)


 

放AC代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int bx,by,mx,my;
 4 long long dp[2][40];
 5 int s[40][40];
 6 int main()
 7 {
 8     cin>>bx>>by>>mx>>my;
 9     bx+=2; by+=2; mx+=2; my+=2;
10     dp[1][2]=1;
11     s[mx][my]=1;
12     s[mx-2][my-1]=1; s[mx-2][my+1]=1;
13     s[mx-1][my-2]=1; s[mx-1][my+2]=1;
14     s[mx+1][my-2]=1; s[mx+1][my+2]=1;
15     s[mx+2][my-1]=1; s[mx+2][my+1]=1;
16     for(int i=2;i<=bx;i++)
17     {
18         for(int j=2;j<=by;j++)
19         {
20             if(s[i][j])
21             {
22                 dp[i&1][j]=0;
23                 continue;
24             }
25             dp[i&1][j]=dp[(i-1)&1][j]+dp[i&1][j-1];
26         }
27     }
28     cout<<dp[bx&1][by];
29     return 0;
30 }

 

posted @ 2022-03-25 19:49  爱吃虾滑  阅读(349)  评论(0编辑  收藏  举报