【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;}

0 0
原创粉丝点击