1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

還暦爺がAtCoderにPascalで挑戦② DP1問解きました。

Last updated at Posted at 2023-02-11

おさらい

先輩Coderの方の記事を見るとやはり過去問を順次解いていくのが王道の様です。
しかしながらじっくり勉強するのが子供の頃から苦手な私、
なかなかモチベーションが湧きません。
ということでコンテストで取り組んだけど解けなかった問題を時間をかけて
おさらいすることにしました。
コンテスト中はそれなりに真面目に考えているので初見の問題よりは
頭に残っている分考えやすい様に思います。
ちゃんと理解しないで形だけ覚えても応用が利かないので腑に落ちるまで
考えてみます。
今回は

に取り組んでみました。コンテスト中は全ケースの組み合わせじゃTLE確実だし
と悩んだ結果脱落。
解説を見るとこの問題はDP(動的計画法)で解けるとのこと。
DPとはなんじゃらほいとググっていくつかの記事を見てみました。
分かった様な分からないような…
最小範囲のケースを解決してそれを足場にどんどん範囲を拡げていく感じ?

この問題の場合はまず1種類の硬貨で払える金額のブーリアン配列を作っていって
その配列の結果に次の種類の硬貨で払える金額を加えていく感じです。
最終的に dp[n][x] の値がtrueになっていれば払えることになります。

var n,x,i,j,v,k : integer;
    a,b : array of integer;
    dp : array[0..50,0..10000] of boolean;

begin
  read(n,x);
  setlength(a,n+1);  // 1オリジンで使うため+1しておく
  setlength(b,n+1);  // a[0],b[0]は使わない
  for i := 0 to 50 do
    for j := 0 to 10000 do
      dp[i][j] := false;
  dp[0][0] := true;
  for i := 1 to n do
    read(a[i],b[i]);
// 硬貨の種類分繰り返し
  for i := 1 to n do
  begin
    // 硬貨の枚数分繰り返し
    for j := 0 to b[i] do
    begin
      v := a[i]*j;  // その枚数での金額
      dp[i][v] := true; 
      // 1つ前の結果に足していく
      for k := 0 to x-v do
        if dp[i-1][k] then 
          dp[i][k+v] := true;
    end;
  end;
  // 最終結果判定
  if dp[n][x] then
    writeln('Yes')
  else
    writeln('No');
 
end.

無事ACとなりました。
次回同類の問題が出た時にうまく応用できるかは自信ないけど。
とりあえずは めでたしめでたし。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?