解题思路 (DP)
假如在给定时间h内,最远到达第个i湖时,最多捕鱼数为F(i, h), 那么问题的解为
MAX{F(i, h)}, i=1...n考虑最远到达第i个湖时,除去路途中的时间,最多的有效捕鱼时间为 hi = h - sum(t[0]+...+t[i-1]), 那么:
F(i, h) <=> maxfish(i, hi)
且有
MAX{F(i, h)} = MAX{maxfish(i, hi)} = MAX{maxfish(1,h1), ..., maxfish(n,hn)}
这里maxfish(i, k)表述为原问题的简化形式:
不考虑湖之间的消耗时间(即t0=t1=...=t[i-1]=0),给定时间k内,在i个湖的最多捕鱼数。
建立递推关系,maxfish(i, k)取下列最大者:
{ k时间内在i-1个湖的最多捕鱼数; k时间内在第i个湖捕鱼时间大于0的所有情况的最多捕鱼数 }
即
maxfish(i, k) = MAX{ maxfish(i-1,k), lakefish(i,j)+maxfish(i-1,k-j) }, 1<j<=k
lakefish(i,j)表示在第i个湖捕鱼j时间能捕到的总鱼数。
原问题MAX{maxfish(i, hi)},只需构造maxfish(n,hn)的解,maxfish(1,h1),...,maxfish(n-1,h[n-1])为过程中更小规模的子问题的解,这n个不同规模的子问题的解的最大者,即为原问题的解。
这个思路的关键在于,将问题简化为不考虑湖之间花费的时间,能更容易使用动态规划来求解。
注意点:
1. 计算过程中h时间转化为单位时间h=h*12, 求解完后输出时间均*5
2. 剩余时间放到第一个湖
代码
#include <iostream>
#include <memory.h>
using namespace std;
int f[26];
int d[26];
int t[25];
int lakefish[26][193];
int maxfish[26][193];
int spent[26][193];
int spentMax[26];
int main(int argc, char** argv)
{
int cases = 0;
int n, h;
while (cin >> n)
{
if (n > 0 && cases > 0)
{
cout << endl;
}
if (n == 0) { break; }
++ cases;
// input
cin >> h;
h = h * 12;
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];
}
// lakefish(i,j)
memset(lakefish, 0, sizeof(lakefish));
int fk = 0;
for (int i = 1; i <= n; ++i)
{
for (int k = 1; k <= h; ++k)
{
fk = f[i] - d[i] * (k - 1);
if (fk > 0)
{
lakefish[i][k] = lakefish[i][k-1] + fk;
}
else
{
lakefish[i][k] = lakefish[i][k-1];
}
}
}
// 1. maxfish(i, k) = MAX{ maxfish(i-1,k), lakefish(i,j)+maxfish(i-1,k-j)}, 1<j<=k
// 2. result = MAX{maxfish(1,h1), ..., maxfish(n,hn)}
memset(maxfish, 0, sizeof(maxfish));
memset(spent, 0, sizeof(spent));
memset(spentMax, 0, sizeof(spentMax));
int hi = h;
int fishij = -1;
int maxfishnk = -1, maxfishn = -1, maxfishh = -1;
for (int i = 1; i <= n; ++i)
{
hi = hi - t[i-1];
for (int k = 1; k <= hi; ++k)
{
maxfish[i][k] = maxfish[i-1][k];
spent[i][k] = 0;
for (int j = 1; j <= k; ++j)
{
fishij = lakefish[i][j] + maxfish[i-1][k-j];
if (fishij > maxfish[i][k])
{
maxfish[i][k] = fishij;
spent[i][k] = j;
}
}
if (k == hi && maxfish[i][k] > maxfishnk)
{
maxfishnk = maxfish[i][k];
maxfishn = i;
maxfishh = k;
}
}
}
// output
int i = maxfishn;
int k = maxfishh;
while (i > 0)
{
spentMax[i] = spent[i][k];
k = k - spentMax[i];
if (i == 1) { spentMax[i] += k; }
-- i;
}
for (int i = 1; i <= n; ++i)
{
if (i > 1) { cout << ", "; }
cout << spentMax[i]*5;
}
cout << endl << "Number of fish expected: " << maxfishnk <<endl;
}
return 0;
}