P1002 过河卒
这道题是动态规划,找到状态转移方程就行了,
这题就是从左上角走到右下角,求共有多少条路径,那我们可以把这个问题细化,原题是从(0,0)走到(n,m),那如果从(0,0)走到(1,1)有几条路径?很容易知道是两条,第一条是(0,0)走到(0,1),再到(1,1),第二条是(0,0)走到(1,0),再到(1,1),那么我们可以发现,当前格子的路径条数等于它上边格子的路径条数加上它左边格子的路径条数,这里的路径条数指的是从(0,0)到当前格子的路径条数,把这个理解后这个题就好做了,
我们就从(0,0)点开始,不断更新数组就行了,如果遇到马能够拦截的地方,就把当前格子赋值为0,
下面是代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 int n,m,mx,my; 6 long long map[30][30]; 7 bool isma(int x,int y){ 8 if(abs(x-mx)==2&&abs(y-my)==1){ 9 return true; 10 } 11 if(abs(x-mx)==1&&abs(y-my)==2){ 12 return true; 13 } 14 if(x==mx&&y==my){ 15 return true; 16 } 17 return false; 18 } 19 int main(){ 20 scanf("%d%d%d%d",&n,&m,&mx,&my); 21 n+=1; 22 m+=1; 23 mx+=1; 24 my+=1; 25 map[0][1]=1; 26 for(int i=1;i<=n;i++){ 27 for(int j=1;j<=m;j++){ 28 if(!isma(i,j)){ 29 map[i][j]=map[i-1][j]+map[i][j-1]; 30 } 31 else{ 32 map[i][j]=0; 33 } 34 } 35 } 36 cout<<map[n][m]; 37 return 0; 38 }
然后,这个题还有个特点,我们发现,这个状态转移方程每次只要提供当前格子的左边的格子和上边的格子就行了,那在当前格子上面两层的数据就没用了,也就是说,在map数组里,不论什么时候,有用的数据只占两行,那我们就没必要开这么大的数组,把数组第一维改成2就行了,因为有用的数据只有两行,我们先填第一行,然后填第二行,然后这个时候数组已经填满了,这个时候,我们就把原来要放到第三行的数据再放到第一行,因为在有了第三行之后,第一行的数据就没用了,所以覆盖掉就行了,就这样不断的覆盖,所以只要两行就够了,这样能节省空间,这样的方法叫做滚动数组。
用按位与操作,这样数组的一维除了1就是0,
下面是代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 int n,m,mx,my; 6 long long map[2][30]; 7 bool isma(int x,int y){ 8 if(abs(x-mx)==2&&abs(y-my)==1){ 9 return true; 10 } 11 if(abs(x-mx)==1&&abs(y-my)==2){ 12 return true; 13 } 14 if(x==mx&&y==my){ 15 return true; 16 } 17 return false; 18 } 19 int main(){ 20 scanf("%d%d%d%d",&n,&m,&mx,&my); 21 n+=1; 22 m+=1; 23 mx+=1; 24 my+=1; 25 map[0][1]=1; 26 for(int i=1;i<=n;i++){ 27 for(int j=1;j<=m;j++){ 28 if(!isma(i,j)){ 29 map[i&1][j]=map[(i-1)&1][j]+map[i&1][j-1]; 30 } 31 else{ 32 map[i&1][j]=0; 33 } 34 } 35 } 36 cout<<map[n&1][m]<<endl; 37 return 0; 38 }