洛谷P1002 过河卒的dfs和dp题解

过河卒算是很经典的一道题了吧,NOIP 2002年的题目,我在学习递推的时候遇上的,明明是一道dp题,我看数据不是非常大(1≤n,m≤20,0≤马的坐标≤20)然后我就试了一下dfs,想练练手防止搜索忘了。
上代码:

#include 
#include 
#include 
using namespace std;
int ans = 0;
bool vis[25][25];
int a, b, n, m;
int x[] = {0, 1, 0};
int y[] = {0, 0, 1};
int d[9][2] = {{0, 0}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};//马的活动范围

bool judge(int temx, int temy)//返回true为马可以抓住卒,false则不能
{
    for(int i = 0; i < 9; i++)
    {
        if(a + d[i][0] == temx && b + d[i][1] == temy) return true;        
    }
    return false;
}

void dfs(int temx, int temy)
{
    if(temx > n || temx < 0 || temy > m || temy < 0 || judge(temx, temy)) return ;
    if(temx == n && temy == m)
    {
        ans ++;
        return ;
    }
    for(int i = 1; i <= 2; i++)
    {
        if(vis[temx + x[i]][temy + y[i]])
        {
            vis[temx + x[i]][temy + y[i]] = false;
            dfs(temx + x[i], temy + y[i]);
            vis[temx + x[i]][temy + y[i]] = true;
        }
    }
    return ;
}


int main()
{
    memset(vis, true, sizeof(vis));
    scanf("%d%d%d%d", &n, &m, &a, &b);
    dfs(0, 0);
    printf("%d\n", ans);
    return 0;
}

提交过后:
洛谷P1002 过河卒的dfs和dp题解_第1张图片
完美T掉三个点。
我就想为啥,后来发现递归40次到没多大事,但是在20*20的时候有C(20,40)种,至少为10的20次方种可能性,那不绝对T掉了吗T^T

后来重新老老实实地写了个dp:

#include 
#include 
#include 
using namespace std;
int ans = 0;
typedef long long ll;
ll vis[25][25];
int a, b, n, m;
int x[] = {0, 1, 0};
int y[] = {0, 0, 1};
int d[9][2] = {{0, 0}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};//马的活动范围

bool judge(int temx, int temy)//返回true为马可以抓住卒,false则不能
{
    for(int i = 0; i < 9; i++)
    {
        if(a + d[i][0] >= 0 && a + d[i][0] < n && b + d[i][1] >=0 && b + d[i][1] <=m)
        {
            if(a + d[i][0] == temx && b + d[i][1] == temy) return true;        
        }
    }
    return false;
}

int main()
{
    memset(vis, 0, sizeof(vis));
    scanf("%d%d%d%d", &n, &m, &a, &b);
    if(judge(0,0)) vis[0][0] = 0;
    else vis[0][0] = 1;
    for(int i = 0; i <= n; i++)
    {
        for(int j = 0; j<= m; j++)
        {
            if(!judge(i, j))
            {
                if(i!=0) vis[i][j] += vis[i-1][j];
                if(j!=0) vis[i][j] += vis[i][j-1];
            }
        }
    }
    printf("%lld\n", vis[n][m]);
    return 0;
}

提交了一下:
洛谷P1002 过河卒的dfs和dp题解_第2张图片
完美~
总结一下:
做题前先估算一下数据规模再写,别好不容易写完发现T了又要重新优化;
遇到状态转移的情况,后面状况受前面的状况影响时,考虑用dp;
dp的话累和数据可能很大,注意考虑数据结构和优化。

你可能感兴趣的:(刷题总结)