過河卒問題(動態規劃問題)
(個人結題思路記錄)
(cr洛谷 過河卒)
棋盤上 A 點有一個過河卒,需要走到目標 BB 點。卒行走的規則:可以向下、或者向右。同時在棋盤上 C 點有一個對方的馬,該馬所在的點和所有跳躍一步可達的點稱爲對方馬的控制點。因此稱之爲“馬攔過河卒”。
棋盤用座標表示,A 點 (0, 0)(0,0)、B 點 (n, m)(n,m),同樣馬的位置座標是需要給出的。
現在要求你計算出卒從 AA 點能夠到達 BB 點的路徑的條數,假設馬的位置是固定不動的,並不是卒走一步馬走一步。
輸入格式
一行四個正整數,分別表示 BB 點座標和馬的座標。
輸出格式
一個整數,表示所有的路徑條數。
輸入輸出樣例
輸入 #1
6 6 3 3
輸出 #1
6
解題過程:一開始用的dfs,數據小的時候能解出來,但是大了會超時,基本思路就是最典型的dfs模型套用。下面是c++代碼:
#include<iostream>
using namespace std;
int n,m,x,y;
long long cnt;
int map[24][24];
int dx[2]={1,0};
int dy[2]={0,1};
//基本超過輸入的nm基本超過15,運算起來就會超時了
//而且得出的cnt非常大,要注意定義數據類型,int肯定是不夠
int search(int xx,int yy)
{
//最基本的dfs搜索模型套用
for(int i=0;i<2;i++)
{
int bx=xx+dx[i];
int by=yy+dy[i];
if(map[bx][by]==0 && bx>=0 && bx<=n && by>=0 && by<=m)
{
map[bx][by]=1;
if(bx==n &&by==m) cnt++;
else search(bx,by);
map[bx][by]=0;//回溯
}
}
}
int main(){
cin>>n>>m>>x>>y;
map[x][y]=-1;
//標記馬控制的點 ,這裏寫的有點麻煩了,可以定義數據用循環實現的
if(x+1>=0&&x+1<=n&&y-2>=0&&y-2<=m) map[x+1][y-2]=-1;
if(x+2>=0&&x+2<=n&&y-1>=0&&y-1<=m) map[x+2][y-1]=-1;
if(x+2>=0&&x+2<=n&&y+1>=0&&y+1<=m) map[x+2][y+1]=-1;
if(x+1>=0&&x+1<=n&&y+2>=0&&y+2<=m) map[x+1][y+2]=-1;
if(x-1>=0&&x-1<=n&&y+2>=0&&y+2<=m) map[x-1][y+2]=-1;
if(x-2>=0&&x-2<=n&&y+1>=0&&y+1<=m) map[x-2][y+1]=-1;
if(x-2>=0&&x-2<=n&&y-1>=0&&y-1<=m) map[x-2][y-1]=-1;
if(x-1>=0&&x-1<=n&&y-2>=0&&y-2<=m) map[x-1][y-2]=-1;
if(map[n][m]==-1) cnt=0;//如果b點在馬控制的位置那麼是無法到的
else search(0,0);
cout<<cnt;
return 0;
}
應用動態規劃思想求解思路
基本上也是很基礎的思路,首先考慮邊界,然後就是狀態轉移方程。不難想出,想要到達i,j位置,有兩條路徑:從i-1,j,以及,i,j-1,所以可以得出如果我們用f[][]來記錄到達i,j的路徑數,那麼f[i][j]=f[i-1][j]+f[i][j-1],但是應用之後會發現有問題,正確的狀態轉移方程應該是f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]),爲啥,測幾組數據就想明白了。
#include<iostream>
#include<algorithm>
using namespace std;
int fx[9]={0,-2,-1,1,2,2,1,-1,-2};
int fy[9]={0,1,2,2,1,-1,-2,-2,-1};
//這是所有馬能走到的位置
int s[30][30];//記錄當前位置是不是馬控制的點
long long f[30][30];//記錄從0,0到大i,j的線路數,數值可能會很大,注意數據類型
int main(){
int n,m,x,y;
cin>>n>>m>>x>>y;
n+=2;m+=2;x+=2;y+=2;
//防止數組越界出錯
f[2][2]=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]=max(f[i][j],f[i-1][j]+f[i][j-1]);
//狀態轉移方程, 注意
/*注意,這裏如果直接f[i][j]=f[i-1][j]+f[i][j-1]是計算不出的*/
}
cout<<f[n][m];
}