过河卒算是很经典的一道题了吧,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;
}
提交过后:
完美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;
}
提交了一下:
完美~
总结一下:
做题前先估算一下数据规模再写,别好不容易写完发现T了又要重新优化;
遇到状态转移的情况,后面状况受前面的状况影响时,考虑用dp;
dp的话累和数据可能很大,注意考虑数据结构和优化。