1.お互いを攻撃しない兵士
n個の正方形の1次元のチェス盤があります。ボードには好きなだけ兵士を置くことができます。(各グリッドには1人の兵士しか配置できません)。兵士は彼の隣の2つの広場の兵士を攻撃します。では、チェス盤の兵士同士がお互いに攻撃しないようにするには、いくつの配置計画が必要ですか?
グリッドに兵士がいない場合は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;
}
フロイドの時間の複雑さは 、幅優先bfsに切り替えると、時間の複雑さは
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;
}
明らかにフロイドより速い。