競賽算法之求解動態規劃問題練習題(c++)-1

過河卒問題(動態規劃問題)

(個人結題思路記錄)

(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];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章