Luogu 興味深い質問 [川を渡るポーン] 参考質問の解決策

背景

今日羅谷を訪れたときにこの質問に気づきました。元の質問は [P1002 [NOIP2002 Popularization Group] Crossing the River - Luogu | New Ecology of Computer Science] に関連しています。教育 (luogu.com.cn)]

チェスが大好きな私にとって、それはもちろん必須の質問です。

質問の意味

ポーンの開始点は左上隅 (0,0) にあり、プログラムは 2 つの座標を受け取ります。ポーンのターゲット ポイントの右下隅 (end_x、end_y) と、敵の馬の座標点 ( horse_x、horse_y)。

このうちポーンは右か下に1マスしか移動できず、ナイトの足元や位置を通過することはできず、最大9点を通過することはできません。

左上隅から右下隅までに解がいくつあるかを求めます。データボリュームの合意された最大座標値は 20 を超えてはなりません。

解析する

一見すると、これは再帰的アルゴリズムの試験問題であることがわかります。この問題では、対象点の解の数を表す解の公式は次のようになります。

res(end_x,end_y)=res(end_x-1,end_y)+res(end_x,end_y-1)

ここで、res(0,0)=1

この問題を効果的に解決するために、(0,0) から開始し、キューの先入れ先出しデータ構造を使用します。

1 つのポイントが 2 つのポイントによって到着する可能性があるため、重複を削除するには、フラグ配列 flag と double queue を使用して、各ポイントが最大 1 回だけキューに入れられるようにする必要があります。

敵馬の存在を考慮して、馬の足元と馬の位置にマイナス値を追加します。これらのマイナス値の位置を通過するたびにチームに加わりません。そうでない場合は、チームに加わり、この位置をマークします. 次回このポジションを検索するときは、チームに参加し続けるプランの数のみを追加します。

キューが完全に空になると、res(end_x,end_y) という結果が出力されます。

時間計算量 O(n^2)、空間計算量 O(n^2)

コード

#include<bits/stdc++.h>
using namespace std;

class point {
	public:
		int x,y;
};

int main() {
	int start_x=0,start_y=0;
	int horse_x,horse_y;
	int end_x,end_y;
	cin>>end_x>>end_y>>horse_x>>horse_y;

	long long res[21][21]= {0};
	res[0][0]=1;
	bool flag[21][21]= {0};

	int horse_direct[][2]= {
		{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}
	};
	res[horse_x][horse_y]=-1;
	for(int k=0; k<8; k++) {
		int x=horse_x+horse_direct[k][0];
		int y=horse_y+horse_direct[k][1];
		if(x>=0&&y>=0&&x<=end_x&&y<=end_y) {
			res[x][y]=-1;
		}
	}

	int soldier_direct[][2]= {
   
   {0,1},{1,0}};

	queue<point> q;
	q.push({start_x,start_y});

	while(!q.empty()) {
		queue<point> nq;
		memset(flag,0,sizeof(flag));
		while(!q.empty()) {
			point p=q.front();
			q.pop();

			for(int k=0; k<2; k++) {
				int x=p.x+soldier_direct[k][0];
				int y=p.y+soldier_direct[k][1];

				if(x<0||y<0||x>end_x||y>end_y) {
					continue;
				}
				if(res[x][y]<0) {
					continue;
				}

				res[x][y]+=res[p.x][p.y];
				if(!flag[x][y]) {
					nq.push({x,y});
					flag[x][y]=1;
				}
			}
		}
		q=nq;
	}
	
	cout<<res[end_x][end_y]<<endl;

	return 0;
}

提出する

おすすめ

転載: blog.csdn.net/qq_36694133/article/details/134108517