NOIP 2002 马拦过河卒 BFS+递推

来源:互联网 发布:如来神掌裹裹抢单软件 编辑:程序博客网 时间:2024/05/16 05:46
Description :

如图,A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。


同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为方马的控制点。例如上图C点上的马可以控制9个点(图中的P1,P2...P8和C)。卒不能通过对方的控制点。
棋盘用坐标表示,A点(0,0)、B点(n, m)(n,m为不超过20的整数,并由键盘输入),同样马的位置坐标是需要给出的(约定:C≠A,同时C≠B)。现在要求你计算出卒从A点能够到达B点的路 径的条数。


Input

B点的坐标(n,m)以及对方马的坐标(X,Y) {不用判错}

Output

一个整数(路径的条数)。

Sample Input
6 6 3 2

 

Sample Output
17


本题要求的是方案数  一般的想法是直接广搜  每到终点一次ans+1  然而这样需要耗费大量时间

经过仔细分析题目发现 :以为卒只能向右或向下 所以每个能到达的点的ans值都只和它左边和上面那个

点有关 所以能得到 ans[x][y]=ans[x-1][y]+ans[x][y-1]这样的递推公式


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;struct node{  int x,y;};int fx[2][2]={1,0,0,1};int mfx[8][2]={-2,-1,-2,1,2,-1,2,1,1,2,-1,2,1,-2,-1,-2};long long vis[30][30];int m,n,ex,ey;void init()  //初始化{    for(int i=0;i<30;i++)        for(int j=0;j<30;j++)        vis[i][j]=0;    return;}long long pd(int a,int b){    if(a<0||b<0)        return 0;    if(vis[a][b]==-1)        return 0;    return vis[a][b];}long long bfs(){    int i;    queue<node>q;    node now;    int tx,ty;    for(i=0;i<8;i++)  //马控制的区域    {        tx=m+mfx[i][0];        ty=n+mfx[i][1];        if(tx<0||ty<0)            continue;        vis[tx][ty]=-1;    }    vis[m][n]=-1;    q.push((node){0,0});    vis[0][0]=1;    while(!q.empty())    {        now=q.front();   //     cout<<now.x<<' '<<now.y<<' '<<vis[now.x][now.y]<<endl;        q.pop();        for(i=0;i<=1;i++) //两种走法        {            tx=now.x+fx[i][0];            ty=now.y+fx[i][1];            if(vis[tx][ty]!=0||tx>ex||ty>ey)     //不走重复的路(剪枝) ||  超过终点了 不能返回  所也不可能(剪枝)                continue;            vis[tx][ty]=pd(tx-1,ty)+pd(tx,ty-1);   //递推 (前值的下标小于0或 被马控制 则返回的值是0)            q.push((node){tx,ty});        }    }    return vis[ex][ey];}int main(){    scanf("%d%d%d%d",&ex,&ey,&m,&n);        init();        printf("%lld\n",bfs());    return 0;}


0 0
原创粉丝点击