1921:【02NOIP普及组】过河卒

1921:【02NOIP普及组】过河卒
【题目描述】
如图,A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。

同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为方马的控制点。例如上图C点上的马可以控制9个点(图中的P1,P2…P8和C)。卒不能通过对方的控制点。
1921:【02NOIP普及组】过河卒_第1张图片

棋盘用坐标表示,A点(0,0)、B点(n, m)(n,m为不超过20的整数,并由键盘输入),同样马 的位置坐标是需要给出的(约定:C≠A,同时C≠B)。现在要求你计算出卒从A点能够到达B点的路径的条数。

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

【输出】
一个整数(路径的条数)。

【输入样例】
6 6 3 2
【输出样例】
17
看到这题我们第一想到暴力,那暴力代码如下

#include
using namespace std;
const int fx[]={0,-2,-1,1,2,2,1,-1,-2};
const int fy[]={0,1,2,2,1,-1,-2,-2,-1};
int dx[]={1,0};
int dy[]={0,1};
int n,m,x,y;
long long ans;
int s[40][40];
void dfs(int xxx,int yyy){
	if(xxx==n&&yyy==m){
		ans++;
		return ;
	}
	for(int i=0;i<2;i++){//暴力枚居所有 可行 
		int xx=xxx+dx[i];
		int yy=yyy+dy[i];
		if(xx>=2&&xx<=n&&yy>=2&&yy<=m&&s[xx][yy]==0){
			s[xx][yy]=1;
			dfs(xx,yy);
			s[xx][yy]=0;
		}
	}
}
int main(){
   cin>>n>>m>>x>>y;
   n+=2;m+=2;x+=2;y+=2;//防越界 
    for(int i=0;i<=8;i++) s[x+fx[i]][y+fy[i]]=1;//标记不能走的地方 
     dfs(2,2);
     cout<<ans;
    return 0;
}

这样只能拿60分因为超时了,而且剪枝似乎也没用,因为ans已经到了long long了
那100分解法如下

#include
using namespace std;
const int fx[]={0,-2,-1,1,2,2,1,-1,-2};
const int fy[]={0,1,2,2,1,-1,-2,-2,-1};
int n,m,x,y;
long long f[40][40];
bool s[40][40];
int main(){
   cin>>n>>m>>x>>y;
   n+=2;m+=2;x+=2;y+=2;//防越界 
    f[2][1]=1;
    s[x][y]=1;
    for(int i=1;i<=8;i++) s[x+fx[i]][y+fy[i]]=1;//标记不能走的地方 
    for(int i=2;i<=n;i++){
        for(int j=2;j<=m;j++){
            if(s[i][j]) continue; 
            f[i][j]=f[i-1][j]+f[i][j-1];//状态转移方程 
        }
    }
   cout<<f[n][m];//结果 
    return 0;
}

原理很简单状态转移方程啊呸呸。

这是小时候大家或多或少见过的题目,就是一点到另一点有多少条路线。而这种题目也很简单,标数法(c++话讲就是递推)你求出到每个点有多少条路线,公式是到上面点的路线数加右边点的路线数就是答案,这也是这类状态转移方程的由来。注意的是起点的x轴与y轴上面的点全为1 ,随后递推出终点

你可能感兴趣的:(暴力,动态规划,数学)