【Codevs】1010 过河卒
来源:互联网 发布:万德数据库 编辑:程序博客网 时间:2024/05/21 20:40
【Codevs】1010 过河卒
题目链接
http://codevs.cn/problem/1010/
题意
如图,A 点有一个过河卒,需要走到目标 B 点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图 C 点上的马可以控制 9 个点(图中的P1,P2 … P8 和 C)。卒不能通过对方马的控制点。
棋盘用坐标表示,A 点(0,0)、B 点(n,m)(n,m 为不超过 20 的整数,并由键盘输入),同样马的位置坐标是需要给出的(约定: C不等于A,同时C不等于B)。现在要求你计算出卒从 A 点能够到达 B 点的路径的条数。
1<=n,m<=15
思路1
深度优先搜索
从A点往左下方搜索,到达一次B点ans++,最后输出答案。
时间复杂度:较大(当n,m范围较大时会超时)
空间复杂度:O(nm)
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int way[8][2]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};int n,m,x,y,ans=0;bool a[100][100]={false};inline void cannotgo(int l,int r){ if(l>=0&&l<=n&&r>=0&&r<=m)a[l][r]=false; return;}inline void start(){ for(int i=0;i<=n;i++) for(int j=0;j<=m;j++)a[i][j]=true; cannotgo(x,y); for(int i=0;i<=7;i++)cannotgo(x+way[i][0],y+way[i][1]); return;}inline void dfs(int l,int r){ if(l==n&&r==m){ ans++; return; } if(a[l+1][r])dfs(l+1,r); if(a[l][r+1])dfs(l,r+1); return;}int main(){ scanf("%d%d%d%d",&n,&m,&x,&y); start(); if(a[0][0])dfs(0,0); printf("%d\n",ans); return 0;}
思路2
广度优先搜索
从A点往左下方搜索,到达一次B点ans++,最后输出答案。
时间复杂度:较大(当n,m范围较大时会超时)
空间复杂度:较大(队列所用空间较大)
代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int way[8][2]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};int n,m,x,y,ans=0;bool a[100][100]={false};inline void cannotgo(int l,int r){ if(l>=0&&l<=n&&r>=0&&r<=m)a[l][r]=false; return;}inline void start(){ for(int i=0;i<=n;i++) for(int j=0;j<=m;j++)a[i][j]=true; cannotgo(x,y); for(int i=0;i<=7;i++)cannotgo(x+way[i][0],y+way[i][1]); return;}inline void bfs(){ queue<int>l,r; while(!l.empty())l.pop(); while(!r.empty())r.pop(); l.push(0); r.push(0); while(!l.empty()){ int ll=l.front(),rr=r.front(); l.pop(); r.pop(); if(ll==n&&rr==m){ ans++; continue; } if(a[ll+1][rr]){ l.push(ll+1); r.push(rr); } if(a[ll][rr+1]){ l.push(ll); r.push(rr+1); } } return;}int main(){ scanf("%d%d%d%d",&n,&m,&x,&y); start(); if(a[0][0])bfs(); printf("%d\n",ans); return 0;}
思路3
动态规划
由思路1和思路2可知,dfs和bfs速度慢是因为dfs和bfs会重复经过同一个点,而要经过一个点(x,y)就必须经过点(x-1,y)或点(x,y-1),所以我们可以用动态规划来做这道题。
动态转移方程如下:
f[i][j]=(a[i][j])?f[i-1][j]+f[i][j-1]:0;(1<=i<=n,i<=j<=m)
初始化:
for(int i=0;i<=n;i++)if(a[i][0])f[i][0]=1;else break;
for(int i=0;i<=m;i++)if(a[0][i])f[0][i]=1;else break;
时间复杂度:O(nm)
空间复杂度:O(nm)
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int way[8][2]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};int n,m,x,y,f[100][100]={0};bool a[100][100]={false};inline void cannotgo(int l,int r){ if(l>=0&&l<=n&&r>=0&&r<=m)a[l][r]=false; return;}inline void start(){ for(int i=0;i<=n;i++) for(int j=0;j<=m;j++)a[i][j]=true; cannotgo(x,y); for(int i=0;i<=7;i++)cannotgo(x+way[i][0],y+way[i][1]); for(int i=0;i<=n;i++)if(a[i][0])f[i][0]=1; else break; for(int i=0;i<=m;i++)if(a[0][i])f[0][i]=1; else break; return;}inline void dp(){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)if(a[i][j])f[i][j]=f[i-1][j]+f[i][j-1]; return;}int main(){ scanf("%d%d%d%d",&n,&m,&x,&y); start(); if(a[0][0])dp(); printf("%d\n",f[n][m]); return 0;}
- 【Codevs】1010 过河卒
- 【codevs 1010】过河卒
- CODEVS 1010过河卒
- CODEVS 1010 过河卒
- codevs 1010 过河卒 dfs
- DFS练习-codevs-1010过河卒
- 【codevs】p1010 过河卒
- CODEVS 1010 过河卒(棋盘型DP)
- Codevs 1010 过河卒== 洛谷 1002
- Codevs 1010 过河卒 2002年NOIP全国联赛普及组
- Codevs 1105 过河
- 【codevs 1730】青蛙过河
- Wikioi-1010-过河卒
- 【wikioi】1010 过河卒
- wikioi 1010 过河卒
- 1010 过河卒
- 1010 过河卒
- 1010 过河卒
- Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) C. Constellation
- [自写]react 编辑工具
- rebmuNdilaV.65
- Bzoj 1001
- socket编程的select模型
- 【Codevs】1010 过河卒
- nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolC
- 警告:不能读取 AppletViewer 的属性文件
- Ant详细教程
- Java设计模式(十六)----迭代子模式
- JDK目录结构
- 最小公倍数 LCM 2
- 例题10-4 UVA 10791 Minimum Sum LCM (最小公倍数的最小和)
- HandlerAPI介绍