(暗記検索)ブルーブリッジカップ2014プロビンシャルコンペティションC /C++グループAプロビンシャルコンペティションZhenti8地下宮殿からの宝物

トピック

キングXには地下の宝庫があります。nxm格子の行列です。各セルに1つの宝物を入れます。各赤ちゃんにはバリューステッカーが貼られています。

地下宮殿への入り口は左上隅にあり、出口は右下隅にあります。

シャオミンは地下宮殿の入り口に連れて行かれ、王は彼に右か下にだけ歩くように頼みました。

特定のグリッドを歩くとき、そのグリッドの宝物の価値がシャオミンの手にあるどの宝物の価値よりも大きい場合、シャオミンはそれを拾うことができます(もちろん、彼はそれを取ることもできません)。

Xiaomingが出口まで歩いたとき、彼の手にある宝物が正確にkである場合、これらの宝物をXiaomingに渡すことができます。

Xiao Mingが、与えられた状況でこれらのk個の財宝を手に入れるために必要なさまざまな行動計画の数を計算するのを手伝ってください。
データ形式
  スペースで区切って3つの整数の行を入力します:nmk(1 <= n、m <= 50、1 <= k <= 12)

次に、n行のデータがあり、各行には、このグリッド上の宝の値を表すm個の整数Ci(0 <= Ci <= 12)があります。

整数を出力する必要があります。これは、k個の宝物のアクションプランの数が正確に取られていることを示します。数値は大きくすることができます。1000000007を法として印刷してください。

たとえば、次のように入力します
  。2 2 2
  1 2
  2 1
  プログラムは次のように出力する必要があります:
  2

別の例として、次のように入力します
  。2 3 2
  1 2 3
  2 1 5
  プログラムは次のように出力する必要があります:
  14

リソースの規則:
  ピークメモリ消費量<256MCPU
  消費量<1000ms

分析する

質問は、下または右にしか行けないことを示しています。ここでは、bfsに直接移動し、可能な限り移動して、実行できるすべての方法を試してください。ここでは、メモリ検索を使用して前の状態を保存する必要があります。次へ必要な時間直接使用する場合、およびkの制限により、剪定することができます

コードセクション

マップ、状態を格納する配列を初期化します

int n,m,k;
int _map[60][60];	//地图 
int cache[51][51][14][14];

bfsパート

プレオーダーでは、最初に現在の状態が保存されているかどうかを判断し、保存されている場合はそれを直接使用してから、境界条件とkを判断し、最後に最後のグリッドが要件を満たしているかどうかを判断します

再帰の後に配置されたバックトラッキング部分は、計算された状態を記録するために使用されます

int bfs(int x,int y,int cnt,int maxv)
{
    
    
	//出口
	int ans=0;
	if(cache[x][y][cnt][maxv]!=-1)
		return cache[x][y][cnt][maxv];
		
	if(x==n||y==m||cnt>k)
		return 0;	
		
	if(x+1==n&&y+1==m)
	{
    
    
		if(cnt==k||(cnt+1==k&&_map[x][y]>maxv))
			ans++;
		return ans;
	}
		
			
	//现在能做的事情
	if(_map[x][y]>maxv)
	{
    
    
		ans+=bfs(x+1,y,cnt+1,_map[x][y]);
		ans+=bfs(x,y+1,cnt+1,_map[x][y]);
	} 
	ans+=bfs(x+1,y,cnt,maxv);
	ans+=bfs(x,y+1,cnt,maxv);
	
	cache[x][y][cnt][maxv]=ans;
	return cache[x][y][cnt][maxv];
}

完全なコード

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

int n,m,k;
int _map[60][60];	//地图 
int cache[51][51][14][14];

int bfs(int x,int y,int cnt,int maxv)
{
    
    
	//出口
	int ans=0;
	if(cache[x][y][cnt][maxv]!=-1)
		return cache[x][y][cnt][maxv];
		
	if(x==n||y==m||cnt>k)
		return 0;	
		
	if(x+1==n&&y+1==m)
	{
    
    
		if(cnt==k||(cnt+1==k&&_map[x][y]>maxv))
			ans++;
		return ans;
	}
		
			
	//现在能做的事情
	if(_map[x][y]>maxv)
	{
    
    
		ans+=bfs(x+1,y,cnt+1,_map[x][y]);
		ans+=bfs(x,y+1,cnt+1,_map[x][y]);
	} 
	ans+=bfs(x+1,y,cnt,maxv);
	ans+=bfs(x,y+1,cnt,maxv);
	
	cache[x][y][cnt][maxv]=ans;
	return cache[x][y][cnt][maxv];
}

int main (void)
{
    
    
	cin>>n>>m>>k;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			cin>>_map[i][j];
			
	memset(cache,-1,sizeof(cache));
	
	cout<<bfs(0,0,0,0);		
		
	return 0;
}

要約する

以前に動的計画法を学んでいたとき、メモ化検索について少し学びました。先生は、メモ化検索の時間計算量を見積もるのは難しいと言いました。動的計画法の時間計算量の約k倍ですが、メモ化検索の方が考えやすいです。約。

おすすめ

転載: blog.csdn.net/weixin_46035615/article/details/123893046