贪心
思路:
按贪心法的原则,要每次都选择能够得到最大收益的湖泊来钓,即钓一次鱼之后,就要再次寻找最优的湖前去钓。这样看起来的话,如何计算路上花费的时间就是一个很纠结的问题。
所以,本题思路的一个关键点在于:究竟需要在路上花费多少时间。
通过例子来说明。
假设现在有3个湖,编号为1、2、3,现提出两种钓鱼方案:
(1)1->3->2->3->1
(2)1->1->2->3->3
这两种方案,单看路上花费的时间,显然方案2更优。而这两种方案所得的鱼量呢?仔细想想,事实上没有区别。
也就是说,只要确定了最远要走到哪个湖,并按照贪心算法作出了第一种方案,那么完全可以将路线转换为方案二,鱼量不会有任何损失。
那么你在路上所花费的总时间就已经确定了,也就是一条直线走到最后所需的时间。
Ps:对本题,若所有湖都已经空了,并且时间还有剩余,默认要把剩余时间全部计入第一个湖的时间。
参考:https://blog.csdn.net/harrypoirot/article/details/25073835
AC代码:
//贪心算法
#include <iostream>
#include <cstring>
using namespace std;
int ans[30][30], f[30], d[30], t[30];
int main() {
int h, n;//时间,湖泊数
cin >> n;
while (true) {
if (n == 0) break;
cin >> h;
h *= 12;
memset(ans, 0, sizeof(ans));
memset(f, 0, sizeof(f));
memset(t, 0, sizeof(t));
memset(d, 0, sizeof(d));
for (int i = 1; i <= n; i++)
cin >> f[i];
for (int i = 1; i <= n; i++)
cin >> d[i];
for (int i = 1; i < n; i++)
cin >> t[i];
int ht, ft[30];
for (int ed = 1; ed <= n; ed++) {//枚举最远会走到哪个湖
memset(ft, 0, sizeof(ft));
for (int i = 1; i <= ed; i++)
ft[i] = f[i];//ft作为f的临时记录
ht = h;//记录剩余时间
for (int i = 1; i < ed; i++)
ht -= t[i];//减去路上的时间花费
int k, emp = 1;//emp标记连续的已经空了的湖
while (ht > 0 && emp <= ed) {//时间用完或湖空为止
k = 1;
for (int j = emp; j <= ed; j++) {//找出最优的湖
if (ft[j] > ft[k])
k = j;
}
ans[ed][0] += ft[k];//此次收获+ft[k]
++ans[ed][k];//记录在k湖花费了1单位时间
--ht;//时间消耗1单位
ft[k] -= d[k];//鱼减少
ft[k] = ft[k] > 0 ? ft[k] : 0;
for (int j = emp; j <= ed; j++) {//检查空湖
if (ft[j] == 0) ++emp;
else break;
}
}
if (ht > 0)//时间剩余,加到第1个湖
ans[ed][1] += ht;
}
int a = 1;
for (int i = 2; i <= n; i++) {//找出收益最大的方案
if (ans[i][0] > ans[a][0])
a = i;
}
for (int i = 1; i <= n; i++) {
cout << ans[a][i] * 5;
if (i != n) cout << ", ";
}
cout << endl;
cout << "Number of fish expected: " << ans[a][0] << endl;
cin >> n;
if (n != 0) cout << endl;
}
return 0;
}