1. 程式人生 > 其它 >ABC 251 | E - Takahashi and Animals

ABC 251 | E - Takahashi and Animals

題意描述

Takahashi有\(N\)頭牛,編號為\(1 \sim N\),他可以通過以下\(N\)種方式來餵養牛:

  • 花費\(A_1\)餵養牛\(1\)和牛\(2\)
  • 花廢\(A_2\)餵養牛\(2\)和牛\(3\)
  • 花費\(A_3\)餵養牛\(3\)和牛\(4\)
  • ... ...
  • 花費\(A_{N - 1}\)餵養牛\(N - 1\)和牛\(N\)
  • 花費\(A_N\)餵養牛\(N\)和牛\(1\)

Takahashi的目標是使得每一頭牛都被餵養,並使得花費最小,輸出該最小花費。

資料範圍

  • \(2 \le N \le 3 \times 10^5\)
  • \(1 \le A_i \le 10^9\)

題目解析

動態規劃問題常用來解決最優化問題,而動態規劃應用於這類問題的優勢在於解決了重疊子問題,避免重複計算。動態規劃演算法的關鍵在於狀態表示和狀態轉移。
首先對問題進行分析

  • 若想牛\(1\)被餵養,操作\(1\)和操作\(N\)需至少選擇一個
  • 若想牛\(2\)被餵養,操作\(1\)和操作\(2\)需至少選擇一個
  • 若想牛\(3\)被餵養,操作\(2\)和操作\(3\)需至少選擇一個
  • ... ...
  • 若想牛\(N - 1\)被餵養,操作\(N - 2\)和操作\(N - 1\)需至少選擇一個
  • 若想牛\(N\)被餵養,操作\(1\)和操作\(N\)需至少選擇一個

狀態表示
\(f[i][0]\)

表示已對前\(i - 1\)個進行決策且第\(i\)個不選的最小費用.
\(f[i][1]\)表示已對前\(i - 1\)個進行決策且第\(i\)個選的最小費用.

狀態轉移
\(f[i][0] = f[i - 1][1]\)
\(f[i][1] = \min(f[i - 1][0], f[i - 1][1]) + a[i]\)

邊界條件及問題答案

  • 若不進行操作\(1\)
    \(f[1][0] = 0, f[1][1] = inf\)
    此時必須進行操作\(N\),故答案為\(f[N][1]\)
  • 若進行操作\(1\)
    \(f[1][1] = a[1], f[1][0] = inf\)
    此時答案為\(\min (f[n][0], f[n][1])\)

將以上兩種情況的答案取最小值作為該問題的答案。

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 3e5 + 10;

ll f[N][2];
ll a[N];
int n;

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);

    ll ans = 1e18;

    //不選1
    f[1][0] = 0, f[1][1]= 1e18;
    for(int i = 2; i <= n; i ++){
        f[i][0] = f[i - 1][1];
        f[i][1] = min(f[i - 1][1], f[i - 1][0]) + a[i];
    }
    ans = min(ans, f[n][1]);

    //選1
    f[1][0] = 1e18, f[1][1]= a[1];
    for(int i = 2; i <= n; i ++){
        f[i][0] = f[i - 1][1];
        f[i][1] = min(f[i - 1][1], f[i - 1][0]) + a[i];
    }
    ans = min(ans, f[n][1]);
    ans = min(ans, f[n][0]);

    printf("%lld\n", ans);

    return 0;
}