洛谷P1809 过河问题 经典贪心问题

  • 作者:zifeiy
  • 标签:贪心

题目链接:https://www.luogu.org/problem/P1809

我们假设第 \(i\) 个人过河的耗时是 \(t[i]\) ,并且 \(t[i]\) 按照从小到大进行了排序(即: \(t[i] \le t[i+1]\) ), 并且设状态 \(f[i]\) 表示前 \(i\) 个人过河的最小花费。
此处我们的贪心基于这样一种思想:优先令 \(t[i]\) 大的过河。
那么:
\(i = 1\) 时,只有一个人,所以此时 \(f[1] = t[1]\)
\(i = 2\) 时,只有两个人,所以此时 \(f[2] = t[2]\)
\(i = 3\) 时,我们可以选择第1个人陪第2个人过去,再回来接第3个人;或者第1个人陪第3个人过去,再回来接第2个人,两种情况下都满足 \(f[3] = t[2] + t[1] + t[3]\)
\(i \gt 3\) 时,我们要送走第 \(i\) 个人,有两种方式:

  • 方式一:第1个人和第i个人过河,第1个人再回来,此时 \(f[i] = f[i-1] + t[i] + t[1]\)
  • 方式二:第1个人和第2个人过河,第2个人再回来,第i-1个人和第i个人过来,第1个人再回来(或者:第1个人和第2个人过河,第1个人再回来,第i-1个人和第i个人多来,第2个人再回来),此时状态变化到了 \(f[i-2]\) ,此时 \(f[i] = f[i-2] + t[2] + t[2] + t[i] + t[1]\)

所以,当 \(i \gt 3\) 时, \(f[i] = \max(f[i-1] + t[i] + t[1] , f[i-2] + t[2] + t[2] + t[i] + t[1])\)

其实我们可以发现,对于任意一个 \(f[i]\) ,它的状态都是由 \(f[j] (j \gt i)\) 演变过来的,但是我们可以通过先求解 \(f[i]\) ,推导出 \(f[j]\) ,最终获得我们的答案—— \(f[n]\)

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, t[maxn], f[maxn];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> t[i];
    sort(t+1, t+1+n);
    for (int i = 1; i <= n; i ++) {
        if (i == 1) f[i] = t[i];
        else if (i == 2) f[i] = t[2];
        else if (i == 3) f[i] = t[2] + t[1] + t[3];
        else f[i] = min(f[i-1]+t[i]+t[1], f[i-2]+t[2]+t[2]+t[i]+t[1]);
    }
    cout << f[n] << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/codedecision/p/11654504.html
今日推荐