DPエントリ概要タイトル
PS:いくつかのDPシンプルなエントリ概要タイトルは、間違っている場合、また、指摘したいと考えて、自分自身のレビューのためにのみ使用され(これはエントリーレベルの完全なタイトルです)
ダイナミックプログラミング(動的計画法)、DPと呼ばれる、話題のこのタイプは最も柔軟なアルゴリズムコンテストコンテンツの一つであると言うことができる、経験を必要とし、時にはあなたが変換したい状態を見つけることができれば、タイトルが表示されます、少しのインスピレーションを必要とします非常にシンプル。
ダイナミックプログラミングは、最適化問題は、この方法ではなく、特別なアルゴリズムを解決するためのプログラミング手法です。
このようなトピックは非常に難しく、間隔DP、DPの木、デジタルDP、DPの確率など、ここでの唯一の最も単純な二次元線形DPおよびDPことができます。
DPは、最も重要なことはすることですされた状態遷移方程式を見つけます
A-階段問題
問題の説明
Mクラスの階段の合計では、プライマリまたはセカンダリへの唯一のステップは、最初のMクラス、どのように多くの移動の合計を行くことができた場合に最初にあなたは、第一段階である、ありますか?
入力
まず、入力データがNの整数含まれ、テストケースの数は、その後、N行のデータは、各行が整数Mを(1 <= M <= 40)が含まれ、階段の段数を示しています。
出力
異なる移動の各テストケースのために、出力Aの数
サンプル入力
2
2
3
サンプル出力
1
2
問題解決:この質問は、DPの単純な問題では
種の総数は最初のn個の階段をシークするとき、n番目の状態に移動する
と、それは容易である状態遷移方程式を知っている:
F [N] = F [N -1] + F [N-2
] :この問題は、三の実装コードの実装方法有する充填法、ブラシ法テーブル、メモリ検索
ここで直接白Iとしてシート法、予め直撃テーブルを(使用しますお気に入りは)テーブルを再生することです
#include<cstdio>
#define ll long long
using namespace std;
ll f[100];
int main()
{
for(int i=1;i<=40;i++)
{
if(i==1||i==2)
f[i]=1;
else
f[i]=f[i-1]+f[i-2]; //状态转移方程
}
ll n;
ll m;
scanf("%lld",&n);
while(n--)
{
scanf("%lld",&m);
printf("%lld\n",f[m]);
}
return 0;
}
B-タワー多くの問題
図は、デジタル三角形であり、経路における下のどこかに上から計算するためのプログラムを書くように経路を通る最大のデジタルサム。
7
3 8
8 1 0
2 7 4 4
1。各ステップは、ダウンしたり、左下右斜めのスラッシュすることができます。
2. 1<=三角形行数<=100
3。デジタル三角形は0、1、...、99の整数です。
4。多くの例がある場合の結果は、出力のいずれか1種最大ことができます。
入力:
整数Nの最初の行は、三角形、行の数を表します。
次のN行、デジタル三角形を記載します。
出力:
第一行一个整数,代表路径所经过底数字总和。
第二行N个数,代表所经过的数字。
例:
入力:
4
。7
。3. 8
。8 1 0
2 7 4 4
出力:
25
7. 8. 7. 3。
溶液は:この質問は、もちろん質問DP水である
:次いでにF [i] [j]がそこを通って配置されている三角形の底辺に第i行j列目の要素の位置からのデジタル和の最大値を示し
た状態遷移式です:F [I] [J] =
MAX(F [I + 1] [J]、F [I + 1] [J + 1])+ [I] [J] もちろん、この問題の二つの方法、aが存在します使用が上部、下からプッシュプッシュする上から下に種下から上へ押さ、
次のように、コードは次のとおりです。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[105][105],f[105][105];
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
for(int j=0;j<=i;j++)
scanf("%d",&a[i][j]);
}
for(int i=0;i<n;i++)
f[n-1][i]=a[n-1][i]; //先将最后一行存入到f数组中
for(int i=n-1;i>=0;i--)
{
for(int j=0;j<=i;j++)
f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j]; //状态转移方程
}
printf("%d\n",f[0][0]);
int num,j=0;
printf("%d",a[0][0]);
for(int i=1;i<n;i++) //寻找所经过的数
{
num=f[i-1][j]-a[i-1][j];
if(num==f[i][j+1])
j++;
printf(" %d",a[i][j]);
}
printf("\n");
return 0;
}
C:0-1ナップザック問題
PS:ここではもちろん0-1ナップザック問題は、最も基本的な、裸のバックパックです0-1
B -ボーン・コレクターHDU -2602
何年も前に、テディの故郷で「ボーン・コレクター」と呼ばれた男がありました。コレクトな犬のよう骨の変動する、牛のが好きこの男は、また、彼は墓に行ってきました...
、骨のコレクタはVの体積が大きな袋を持っていて、収集の彼の旅に沿って骨の多くは、明らかにあります別の骨は今彼の旅に沿って各ボーンの値与えられた、異なる値と異なるボリュームを持っている、あなたは骨のコレクターが得ることができる合計値の最大値を計算することができますか?
入力
最初の行は整数T、ケースの数を含みます。
Tケース続いて、それぞれの場合三行、最初の行は、骨の数と彼の袋の容積を表すN、V、(N <= 1000、V <= 1000)の整数2を含みます。そして、2行目は、各骨の値を表すNの整数が含まれています。第三のラインは、各骨の体積を表すN個の整数を含みます。
出力
合計値の最大値を表す1行に1つの整数(この数が2未満で31あろう)。
サンプル入力
1
5 10
1 2 3 4 5
5 4 3 2 1
サンプル出力
14
ソリューション:私たちは、その後の状態との状態遷移方程式分析し、これは裸の0-1ナップザック問題であることがわかります
。状態を
i番目の記事、jへのバックパックの容量は、あなたが最も価値を得ることができます前に、
状態遷移方程式:
記事のi番目の顔、何も取らない二つ以上の選択肢を取るか
[i]は、物品の重量wが<この時点であればバックパックjの容量を
フィットは取らないように選択することができますメートルを[i]を[ J] = M [I-1
場合J> = [i]は、wを
取ることを選択し、あなたがW [i]を取得した値m [I-1] [JWのための余地を作るために必要な+ V [i]は
M [I-1] [、上記のように、状況を取るしないことを選択し
最大値であるいずれか、
である:
IF(J> = W [I])
M [I] [J] =最大(M [1-I]、[J]、M [1-I。] [JW [I] + V [I]);
他
M [I] [J] = M [J] [1-I];
例:
次のようによって、この質問のコードは次のとおりです。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int value[1010],weight[1010],m[1010][1010];
//分别表示骨头的价值,重量,以及状态转移方程 重点解释m[i][j]:i表示价值域,j表示重量域
int t,n,v;
int main()
{
scanf("%d",&t);
while(t--)
{
memset(value,0,sizeof(value));
memset(weight,0,sizeof(weight));
memset(m,0,sizeof(m));
scanf("%d%d",&n,&v);
for(int i=1;i<=n;i++)
scanf("%d",&value[i]);
for(int i=1;i<=n;i++)
scanf("%d",&weight[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=v;j++) //从0开始,意味着重量为0也可以计算
{
if(j>=weight[i])
m[i][j]=max(m[i-1][j],m[i-1][j-weight[i]]+value[i]); //状态转移方程
else
m[i][j]=m[i-1][j];
}
}
printf("%d\n",m[n][v]);
}
return 0;
}
D-上昇最長シーケンス
例:POJ:2533
サンプル入力
7。
1. 7 8 4 3 5 9。
サンプル出力
4
溶液:同一の状態の分析との状態遷移方程式
状態:
Fに[i]はiは終了番号を生成する前に、以前にシーケンス番号の最大増加を示し
た状態遷移式:
F [I] = MAX(Fを[I]、F [J] +1)
そして、次のコード:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
int a[1010],f[1010];
int main()
{
int n;
int num=0;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
f[i]=1; //初始化
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=i; j++)
if(a[j]<a[i])
f[i]=max(f[i],f[j]+1); //状态转移方程
}
for(int i=1;i<=n;i++)
num=max(num,f[i]); //找最长上升子序列长度
printf("%d\n",num);
return 0;
}
E-最長共通部分列
例:POJ:1458
サンプル入力
abcfbc abfcab
プログラミングコンテストザ・
ABCDのMNP
サンプル出力
4
2
0
溶液:同じ状態の状態遷移方程式分析
状態:
Fに[i] [j]は得ることができ、最初の文字とS2 jの前に第2の文字列の前に最長共通ストリングS1 Iを意味しますシーケンスの
状態遷移式:
IF(SL [-I 1] == S2 [-J 1。])
F [I] [J] = F [1-I]、[J-1]を+1しました;
他
F [I] [ J] = MAX(F [I -1] [J]、F [i]は[J-1]);
例えば:
これ以下のような問題のコードであること。
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
int f[1010][1010];
int main()
{
ios::sync_with_stdio(false);
string S1,S2;
while(cin>>S1>>S2)
{
memset(f,0,sizeof(f));
int len1=S1.length();
int len2=S2.length();
for(int i=1;i<=len1;i++)
{
for(int j=1;j<=len2;j++)
{
if(S1[i-1]==S2[j-1])
f[i][j]=f[i-1][j-1]+1;
else
f[i][j]=max(f[i-1][j],f[i][j-1]); //状态转移方程
}
}
printf("%d\n",f[len1][len2]);
}
return 0;
}
これらは、いくつかの簡単な質問DPエントリの要約それです!!!
PS:DPサイクルにおける白FOUNDは1を起動するために非常に簡単のように思えます