解题思路:
这题一看到,卧槽,好简单,无脑dfs就可以走完,于是不到5分钟码出来了个dfs,没想到光荣的T了,,,然后翻了翻题解,才知道要用棋盘dp,以前一直不会,现在就来学学吧。
T的代码:
# include<cstdio>
# include<iostream>
using namespace std;
# define MAX 20
int grid[MAX][MAX];
int vis[MAX][MAX];
int edx,edy;
int mx,my;
int res;
int next[2][2] = { {0,1},{1,0} };
int next2[9][2] = { {0,0},{-1,-2},{-1,2},{-2,-1},{-2,1},{1,-2},{1,2},{2,-1},{2,1} };
int judge ( int x,int y )
{
if ( x < 0||x > edx||y < 0||y > edy||vis[x][y] )
{
return 0;
}
for ( int i = 0;i < 9;i++ )
{
if ( x==mx+next2[i][0] && y==my+next2[i][1] )
{
return 0;
}
}
return 1;
}
void dfs( int x,int y )
{
if ( x == edx && y == edy )
{
res++;
return;
}
for ( int i = 0;i < 2;i++ )
{
int n_x = x+next[i][0];
int n_y = y+next[i][1];
if ( judge(n_x,n_y) )
{
vis[n_x][n_y] = 1;
dfs( n_x,n_y );
vis[n_x][n_y] = 0;
}
}
}
int main(void)
{
while ( cin>>edx>>edy>>mx>>my )
{
vis[0][0] = 1;
dfs( 0,0 );
cout<<res<<endl;
}
return 0;
}
棋盘dp思想:
这道题是一个由于存在无后效性的方法,所以呢,我们应该想到dp的分层处理,就是说,先从左到右走一遍,然后再从上到下走一遍,把其中存在能够走的点晒出来,
不能走的直接break,因为卒只有两种走法,要么从左->右走,要么从上->下的走。然后还需要明确一个就是dp[0][0] = 1.
哦,说了,这么多,都忘记定义这个题的状态和状态转移方程是什么了,我们知道状态就是dp[i][j]表示的是从从(0,0)->(i,j)的方法总数,那我们最后输出dp[edx][edy]就是最终的结果了~
接下来来说说状态转移方程是什么?在最后一个点上,(edx,edy)仅仅可以由两个点走过来,一个点是(edx-1,edy),另一点是(edx,edy-1),然后呢,方法数就可以依次类推了,这样就得到了状态转移方程:dp[i][j] = dp[i-1][j]+dp[i][j-1];
好了,不多说了,上代码:
# include<cstdio>
# include<iostream>
using namespace std;
# define MAX 20
int edx,edy;
int mx,my;
int dp[MAX][MAX];
int next2[9][2] = { {0,0},{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2} };
int judge ( int x,int y )
{
for ( int i = 0;i < 9;i++ )
{
if ( x==mx+next2[i][0] && y==my+next2[i][1] )
{
return 0;
}
}
return 1;
}
int main(void)
{
while ( cin>>edx>>edy>>mx>>my )
{
dp[0][0] = 1;
for ( int i = 1;i <= edx;i++ )
{
if ( judge(i,0) )
{
dp[i][0] = 1;
}
else
{
break;
}
}
for ( int j = 1;j <= edy;j++ )
{
if ( judge(0,j) )
{
dp[0][j] = 1;
}
else
{
break;
}
}
for ( int i = 1;i <= edx;i++ )
{
for ( int j = 1;j <= edy;j++ )
{
if ( judge(i,j) )
{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
cout<<dp[edx][edy]<<endl;
}
return 0;
}