絶望的な、謙虚に前進。
今日、我々は古典的な動的なプログラミングトピック整理と - ブックにコピーし、それを見て、古典的な2次元線形DPの問題です。
タイトル説明
Mのニュースルームは、本の中で皆に配布コピーされた人々は、連続していなければならない複写速度はすべてのために同じである、この本は、2つ(またはそれ以上)のために許可されていませんが、定期的にKの個人的なコピーであることを、この本を与えたいですこのような第一の、第三、第四の同じ人に、この番号を転写することができないとして。今、最短時間をコピーしたプログラムを設計してください。時間の人々のほとんどをコピーすると、ページをコピーする時間を費やしました。
エントリー
1行目二つの整数MとK、K≤M≤500、間にスペースで区切られています。
2行目Mの整数、I-整数私は間にスペースで区切って、本のページ数を表します。
2行目Mの整数、I-整数私は間にスペースで区切って、本のページ数を表します。
輸出
番号を開始2つの正の整数のK行の合計は、i番目の行及びブックのi番目の個別の転写終結番号、二つの数字の間のスペースで区切られたそれぞれを表します。複数の解決策がある場合はKラインは、可能な限りコピーが少ない人の前で、昇順で番号を開始する必要があります。
サンプルの説明:
3つの転写位置それぞれ:
1-5(15)
6-7(13)
8-9(17)
サンプルの説明:
3つの転写位置それぞれ:
1-5(15)
6-7(13)
8-9(17)
サンプル入力
9 3
1 2 3 4 5 6 7 8 9
サンプル出力
5. 1
6 7
8 9
の説明コード:
#include<iostream>
#include<cstring>
using
namespace
std;
int
m,k,a[505],dp[505][505],sum[505],path[505][505];
void
print(
int
i,
int
j){
if
(i==0)
return
;
print(i-1,path[i][j]);
printf
(
"%d %d\n"
,path[i][j]+1,j);
}
int
main(){
scanf
(
"%d%d"
,&m,&k);
for
(
int
i=1;i<=m;i++){
scanf
(
"%d"
,&a[i]);
sum[i]=sum[i-1]+a[i];
}
memset
(dp,0x3f,
sizeof
(dp));
for
(
int
i=1;i<=m-k+1;i++){
dp[1][i]=sum[i];
}
for
(
int
i=2;i<=k;i++){
for
(
int
j=i;j<=m-k+i;j++){
for
(
int
k=i-1;k<j;k++){
if
(max(dp[i-1][k],sum[j]-sum[k])<dp[i][j]){
dp[i][j]=max(dp[i-1][k],sum[j]-sum[k]);
path[i][j]=k;
}
}
}
}
print(k,m);
// printf("%d\n",dp[k][m]);
return
0;
}
問題の解決策のアイデア:
DP [i] [j]は、DP [1] [j]は本jの前の総コピー時間(J人が本を転写)I jのブックの前に個人のコピーの最小時間であることをいう、各ステップ最適解は、DP [I-1] [k]の最適解DP [I] [j]は、jから解決することができる私は、kは、I-1の範囲のM-K + Iを列挙体に列挙の範囲であります{用:J-1は、この時間は(2〜N i)について、実行するために3つのサイクルのために使用される(J:I〜M-K + I){ため(K:I-1〜J-1) }}もし各MAX(DP [I-1] [k]は、和[J] -sum [K])> DP [I]、[J]、割り当てDP [I] [J] = MAX(DP [ I-1] [k]は、和[J] -sum [K])。最終的な取得DP [K] [m]が最適解であるが、二次元アレイの経路[I] [J]を有しますストレージ・パス。再帰的な最終的な出力。