動的プログラミング実験分析

1.お互いを攻撃しない兵士

n個の正方形の1次元のチェス盤があります。ボードには好きなだけ兵士を置くことができます。(各グリッドには1人の兵士しか配置できません)。兵士は彼の隣の2つの広場の兵士を攻撃します。では、チェス盤の兵士同士がお互いに攻撃しないようにするには、いくつの配置計画が必要ですか?

トピックの要件1

グリッドに兵士がいない場合は0を使用し、グリッド内の兵士には1を使用します。1つのグリッド、2つの状態0、1、2つのグリッド00、01、10、3つのグリッド000、001、010、100、101、4つのグリッド0000、0001、0010、0100、1000、1001、1010この質問は非常に単純です。ルールを探すだけですが、実験的なレポートを書いたり、実験的なプロセスを実行したりするためですよ
ね?3つのグリッド0 | 00、0 | 01、0 | 10、10 | 0、10 | 1
4つのグリッド0 | 000、0 | 001、0 | 010、0 | 100、0 | 101、10 | 00、10 | 01,10 | 10

  • 分割された状態(分割されたサブ問題):この問題では、n個の格子の最適解は0とn-1の格子と10個とn-2の格子状態で構成されると考えることができます。
  • 状態の表現:f(n)を使用してnグリッドの配置を示します
  • 状態伝達方程式:f(n)= f(n-1)+ f(n-2)
  • 境界を決定する:最小の問題は1グリッドと2グリッドであり、分割できないため、境界値n = 1およびn = 2

状態遷移方程式と境界値が決定されたので、次の直接解は

#include<iostream>
using namespace std;
int f(int n){
	if(n==1) return 2;
  	else if(n==2) return 3;
  	else return f(n-1)+f(n-2);
}
int main(){
  	int n;
  	cin>>n;
  	cout<<f(n);
	return 0;
}

上記は元のエコロジーコードですが、効率と最適化の問題を考慮して、1次元配列f [n]を使用してチェス盤をシミュレートします。これにより、各州の高速で最適な解が格納されます。

#include<iostream>
using namespace std;
int f[50]={2,3};
int main(){
	for(int i=2;i<50;i++){
		f[i]=f[i-1]+f[i-2];
	}
  	int n;
  	cin>>n;
  	cout<<f[n-1];
	return 0;
}



最適化前と最適化後の効果は明ら​​かです。

2.階段を上る

ある日、2人は1階から始まり、誰がm番目の層に早く到達できるかを確認しました。Aは一度に1層ずつ下がっています。これは明らかに遅すぎます。公平を期すために、Bは複数の一方向を指定しましたFastトラック。1のみを使用して、uレイヤーからvレイヤーに移動できます。隣接するレイヤーには1が必要で、次のレイヤーに移動したり、前のレイヤーに戻したりできることがわかっています。[1、m]レイヤー間でのみ転送できます。つまり、0またはm + 1レイヤーに到達できません。 。Aがm階に到達してBを倒すのに必要な最小時間を計算するのを手伝ってください(元の質問は深刻ではなく、少し変更されています)。

この質問は、各エッジの重みが1であることを除いて、グラフの最短経路に少し似ています。公式のヒントでは、フロイドのアルゴリズムを使用するように言われていますが、私はまったく覚えていません。それをbfsで解決するだけです。しかし、実験には動的プログラミングが必要です。それについて書かせてください。フロイドアルゴリズムについては、以下のリンクを参照してください。

フロイドソリューション

フロイドアルゴリズムの詳細説明

  • つまり、フロイドアルゴリズムの場合、最初に隣接行列dp [n] [n]を確立します。フロイドアルゴリズムの場合、状態遷移方程式はd [i] [j] = min {d [i] [j]、d [i ] [k] + d [k] [j]}
    アルゴリズムは次のとおりです
#include<iostream>
#define INF 1000
using namespace std;

int dp[202][202]={0};

int main(){
    //初始化
  	int n,m;
  	cin>>n>>m;
  	for(int i=0;i<201;i++){
  	    for(int j=0;j<201;j++){
            if(i+1==j||i-1==j)
                dp[i][j]=1;
            else
                dp[i][j]=INF;
  	    }
  	}
  	int i,j;
  	while(n--){
        cin>>i>>j;
        dp[i][j]=1;
  	}
  	//算法
  	for(int k=1;k<=m;k++)
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(dp[i][j]>dp[i][k]+dp[k][j])
                    dp[i][j]=dp[i][k]+dp[k][j];

    cout<<dp[1][m];
	return 0;
}

フロイドの時間の複雑さは O(n ^ 3) 、幅優先bfsに切り替えると、時間の複雑さは O(n)

BFS(幅優先)

アルゴリズムの考え方は、最初にチームの最初の頂点に入り、チームの頭が到達できるすべての場所をトラバースし、次にチームに入り、最初にチームを離れ、キューが空になる(すべての頂点が完了する)まで上記の操作を続けることです。特に、すべてのパスの長さは一意です。

アルゴリズムは次のとおりです

// 构建邻接矩阵
#include<iostream>
#define INF 1000
using namespace std;

int visit[202];
int a[202][202]={0};
void print(int m){
 for(int i=1;i<=m;i++){
        cout<<visit[i]<<" ";
    }cout<<endl;
}
int queue[1000];
int main(){
  	int n,m;
  	cin>>n>>m;
  	for(int i=0;i<201;i++){
        a[i][i+1]=a[i+1][i]=1;
        visit[i]=INF;
  	}
  	int i,j;
  	while(n--){
        cin>>i>>j;
        a[i][j]=1;
  	}

  	visit[1]=0;
  	int f=0,e=0;
    queue[e++]=1;
  	while(f<e){
        int x=queue[f];
        int y=visit[x];
        for(i=1;i<=m;i++){
            if(a[x][i]!=0){
                if(visit[i]>y+1){
                    visit[i]=y+1;
                    queue[e++]=i;
                }
            }
        }
        f++;
  	}
    cout<<visit[m];
	return 0;
}

明らかにフロイドより速い。

オリジナルの記事を3件公開 Like1 Visits 62

おすすめ

転載: blog.csdn.net/weixin_43323747/article/details/105542230