https://www.luogu.org/problem/P1002

题目描述

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

输入描述:

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

输出描述:

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

示例1

输入

   

输出


说明/提示

结果可能很大!

一开始按DFS做,超时

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <math.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
const int INF=0x3f3f3f3f;
typedef long long LL;
const int mod=1e9+;
const double PI=acos(-);
const int maxn=;
using namespace std;
//ios::sync_with_stdio(false);
// cin.tie(NULL); int n,m,x,y;
int ans; bool judge(int a,int b)
{
if(a==x&&b==y)
return false;
if(a==x-&&b==y-)
return false;
if(a==x-&&b==y-)
return false;
if(a==x+&&b==y-)
return false;
if(a==x+&&b==y-)
return false;
if(a==x-&&b==y+)
return false;
if(a==x+&&b==y+)
return false;
if(a==x-&&b==y+)
return false;
if(a==x+&&b==y+)
return false;
return true;
} void DFS(int a,int b)
{
if(a==n&&b==m)
{
ans++;
return ;
}
if(a+<=n&&judge(a+,b))
DFS(a+,b);
if(b+<=m&&judge(a,b+))
DFS(a,b+);
} int main()
{
scanf("%d %d %d %d",&n,&m,&x,&y);
DFS(,);
printf("%d\n",ans);
return ;
}

后来以为if判断太多,换了种方法,依然超时

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <math.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
const int INF=0x3f3f3f3f;
typedef long long LL;
const int mod=1e9+;
const double PI=acos(-);
const int maxn=;
using namespace std;
//ios::sync_with_stdio(false);
// cin.tie(NULL); int n,m,x,y;
int G[][];
int ans; void DFS(int a,int b)
{
if(a==n&&b==m)
{
ans++;
return ;
}
if(a+<=n&&G[a+][b]==)
DFS(a+,b);
if(b+<=m&&G[a][b+]==)
DFS(a,b+);
return ;
} int main()
{
//freopen("testdate.in","r",stdin);
scanf("%d %d %d %d",&n,&m,&x,&y);
G[x][y]=;
if(x->=)
{
G[x-][y-]=;
G[x-][y+]=;
}
if(y->=)
{
G[x-][y-]=;
G[x+][y-]=;
}
if(x->=)
{
G[x-][y+]=;
}
if(y->=)
{
G[x+][y-]=;
}
G[x+][y+]=;
G[x+][y+]=;
DFS(,);
printf("%d\n",ans);
return ;
}

最后意识到,这题没那么简单.

看过题解才明白这题是记忆化递推,或者说是DP

DP题就是要找到状态转移方程,这题的状态转移方程只用手动模拟一下就可以了,就可以得出到每一个点的方案数就是上面和左边的方案数的总和(因为只可以向右走或向下走),具体的状态转移方程是

即可以写成DP[i][j]=max(DP[i][j],DP[i-1][j]+DP[i][j-1])

注意,最大的结果已经超过了int的范围,这是一个坑

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <math.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <math.h>
const int INF=0x3f3f3f3f;
typedef long long LL;
const int mod=1e9+;
const double PI=acos(-);
const int maxn=;
using namespace std;
//ios::sync_with_stdio(false);
// cin.tie(NULL); int n,m,x,y;
LL DP[][];//DP[i][j]代表从A点到(i,j)的线路条数
bool G[][];//判断这个点有没有马盯着
//马可以走到的位置
int fx[]={,-,-,,,,,-,-};
int fy[]={,,,,,-,-,-,-}; int main()
{
scanf("%d %d %d %d",&n,&m,&x,&y);
n+=;m+=,x+=,y+=;//坐标加2,防止标记马时越界
for(int i=;i<=;i++)//标记马的位置
{
G[x+fx[i]][y+fy[i]]=true;
}
DP[][]=;//初始化
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(G[i][j])
continue;
DP[i][j]=max(DP[i][j],DP[i-][j]+DP[i][j-]);//状态转移方程
}
}
printf("%lld\n",DP[n][m]);
return ;
}

下面粘一个有意思的代码(递推):

我们可以发现一个规律:每个数都等于它上面左边的数的和

 #include <iostream>
using namespace std; int n,m,my,mx;
long long a[][]; int main()
{
cin >>n >>m >>my >>mx;//输入数据
n=n+;m=m+;my=my+;mx=mx+; //隔出两格,当要把马可跳到的地方掷成0时不会出错
for(int z=;z<=m;z++)
{
for(int y=;y<=n;y++)
{
a[z][y]=a[z-][y]+a[z][y-]; //将这个数左边和上面的数相加
a[][]=;//由于会把起点掷成0,所以要回归1
a[mx][my]=;//将马的地方掷成0
a[mx+][my+]=;a[mx+][my-]=;//将马可跳到的地方掷成0
a[mx-][my+]=;a[mx-][my-]=;//将马可跳到的地方掷成0
a[mx+][my+]=;a[mx+][my-]=;//将马可跳到的地方掷成0
a[mx-][my+]=;a[mx-][my-]=;//将马可跳到的地方掷成0
}
}
cout <<a[m][n];//输出结果
return ;
}

NOIP2002 过河卒(DFS,DP)的更多相关文章

  1. SDUT 1265-马停下过河卒(DFS)

    马拦过河卒 nid=24#time" title="C.C++.go.haskell.lua.pascal Time Limit3000ms Memory Limit 65536K ...

  2. 洛谷P1002 过河卒【dp】

    棋盘上AA点有一个过河卒,需要走到目标BB点.卒行走的规则:可以向下.或者向右.同时在棋盘上CC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为"马拦过河卒 ...

  3. NOIP 2002过河卒 Label:dp

    题目描述 如图,A 点有一个过河卒,需要走到目标 B 点.卒行走规则:可以向下.或者向右.同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点.例如 ...

  4. P1002 过河卒【dp】

    P1002 过河卒 题目描述 棋盘上AAA点有一个过河卒,需要走到目标BBB点.卒行走的规则:可以向下.或者向右.同时在棋盘上CCC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制 ...

  5. 洛谷 - P1002 - 过河卒 - 简单dp

    https://www.luogu.org/problemnew/show/P1002 方程很好想,题目也很暴力.感谢题目提示数据会很大. #include<bits/stdc++.h> ...

  6. 过河卒(Noip2002)(dp)

    过河卒(Noip2002) 时间限制: 1 Sec  内存限制: 128 MB提交: 7  解决: 6[提交][状态][讨论版][命题人:quanxing] 题目描述 棋盘上A点有一个过河卒,需要走到 ...

  7. dp练习(4)——过河卒

    1010 过河卒 2002年NOIP全国联赛普及组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 如图,A ...

  8. 【openjudge】【递推】例3.6 过河卒(Noip2002)

    [题目描述] 棋盘上A点有一个过河卒,需要走到目标B点.卒行走的规则:可以向下.或者向右.同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1 ...

  9. 过河卒 NOIp 2002 dp

    题目描述 棋盘上AAA点有一个过河卒,需要走到目标BBB点.卒行走的规则:可以向下.或者向右.同时在棋盘上CCC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为“马拦 ...

随机推荐

  1. springboot-war

    预览 1.pom.xml 与springboot-jar-web的区别是: 将 <packaging>jar</packaging> 替换成: <packaging> ...

  2. k8s yaml 文件中字段类型:

    1.<Object>    对象类型 metadata: name: namespace: 2.<[]Object>  对象列表类型 containers: -  name: ...

  3. git 一些操作

    1. 代码相关 克隆代码 git clone xxx.git 拉取代码 git pull 查看 修改的 状态 git status 推送代码 git push add 或者 修改代码之后 回滚到 未修 ...

  4. no.10京东咚咚架构演讲读后感

    京东之与旺旺相当于淘宝,他们都是服务于买家和卖家的沟通.京东咚咚的功能比较简单,实现了一个 IM 的基本功能,接入.互通消息和状态. 另外还有客服功能,就是顾客接入咨询时的客服分配,按轮询方式把顾客分 ...

  5. php对象: __clone, __toString, __call,__isset, __unset, __sleep, __wakeup,

    __clone: 克隆对象,自动完成操作   clone()  __toString:  return返回字符串  __call: 当调用不存在的函数时,自动执行该方法,并返回相关值 __isset: ...

  6. winform屏蔽鼠标右键

    /// <summary> /// 屏蔽右键 /// </summary> internal class MenuHandler : IContextMenuHandler { ...

  7. 代码杂谈-python函数

    发现函数可以设置属性变量, 如下 newfunc.func , newfunc.args def partial(func, *args, **keywords): """ ...

  8. Python—在Django中使用Celery

    一.Django中的请求 Django Web中从一个http请求发起,到获得响应返回html页面的流程大致如下: http请求发起 经过中间件 http handling(request解析) ur ...

  9. Java数据的存储

    在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register).这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据需求进 ...

  10. 普通java项目转换为带有Tomcat的动态Web项目

    原文链接:http://blog.csdn.net/l4432321/article/details/52049125 直接项目右键进入Properties配置,点击Project Facets,再点 ...